From fcb64e3857d9a08fc64f95c987adff57c2114f86 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Tue, 10 Nov 2026 01:09:37 +0100 Subject: [PATCH] feat: full screen keeps its notes on Details The plan, Confirm and the result say what happens, its size, where and the next step. Their counts, free space, backup and save notes, kinds, reasons a file is left out, per-file failures and commands move to a Details screen: d on the plan, Confirm and the result, the Details row on the plan, Y, o or Tab on the result. Opened on the result, they are also said in the terminal after Exit. Installing lists the files that went well only with --verbose, and --verbose draws every line in place. The log line reads Log: so that Details names one thing. --check prints its count, the folder and the remedy in both modes, so that --verbose prints every default line. Each golden screen gets a word budget per size, and a test proves the screen and its Details together equal the --verbose screen. --- install.ps1 | 2 +- install.py | 305 +++++++++++++----- install.sh | 2 +- install/launchers/index.json | 16 +- scripts/generate_installer_doc.py | 2 +- tests/fixtures/tui/colour-120x40.txt | 128 ++++++-- tests/fixtures/tui/colour-40x12.txt | 56 +++- tests/fixtures/tui/colour-40x15.txt | 70 ++-- tests/fixtures/tui/colour-80x24.txt | 98 ++++-- tests/fixtures/tui/confirm-120x40.txt | 6 +- tests/fixtures/tui/confirm-40x12.txt | 6 +- tests/fixtures/tui/confirm-40x15.txt | 6 +- tests/fixtures/tui/confirm-80x24.txt | 6 +- tests/fixtures/tui/help-120x40.txt | 2 +- tests/fixtures/tui/help-40x12.txt | 4 +- tests/fixtures/tui/help-40x15.txt | 2 +- tests/fixtures/tui/help-80x24.txt | 2 +- tests/fixtures/tui/installing-120x40.txt | 2 +- tests/fixtures/tui/installing-40x12.txt | 2 +- tests/fixtures/tui/installing-40x15.txt | 2 +- tests/fixtures/tui/installing-80x24.txt | 2 +- tests/fixtures/tui/plan-120x40.txt | 6 +- tests/fixtures/tui/plan-40x12.txt | 2 +- tests/fixtures/tui/plan-40x15.txt | 6 +- tests/fixtures/tui/plan-80x24.txt | 6 +- tests/fixtures/tui/plan-details-120x40.txt | 40 +++ tests/fixtures/tui/plan-details-40x12.txt | 12 + tests/fixtures/tui/plan-details-40x15.txt | 15 + tests/fixtures/tui/plan-details-80x24.txt | 24 ++ tests/fixtures/tui/plan-games-120x40.txt | 10 +- tests/fixtures/tui/plan-games-40x12.txt | 2 +- tests/fixtures/tui/plan-games-40x15.txt | 2 +- tests/fixtures/tui/plan-games-80x24.txt | 10 +- tests/fixtures/tui/plan-in-place-120x40.txt | 6 +- tests/fixtures/tui/plan-in-place-40x12.txt | 8 +- tests/fixtures/tui/plan-in-place-40x15.txt | 8 +- tests/fixtures/tui/plan-in-place-80x24.txt | 6 +- tests/fixtures/tui/result-120x40.txt | 14 +- tests/fixtures/tui/result-40x12.txt | 6 +- tests/fixtures/tui/result-40x15.txt | 12 +- tests/fixtures/tui/result-80x24.txt | 16 +- tests/fixtures/tui/result-details-120x40.txt | 40 +++ tests/fixtures/tui/result-details-40x12.txt | 12 + tests/fixtures/tui/result-details-40x15.txt | 15 + tests/fixtures/tui/result-details-80x24.txt | 24 ++ tests/fixtures/tui/route-evmapy.txt | 194 ++++++----- tests/fixtures/tui/route-gptokeyb.txt | 196 ++++++----- tests/fixtures/tui/route-gptokeyb_muxterm.txt | 196 ++++++----- tests/fixtures/tui/route-keys.txt | 224 +++++++++---- tests/fixtures/tui/route-miyoo.txt | 179 +++++++--- tests/fixtures/tui/route-muxterm.txt | 200 +++++++++--- tests/test_doc_pages.py | 2 +- tests/test_install.py | 4 +- tests/test_install_tui.py | 269 +++++++++++++-- tests/test_no_game_data.py | 6 +- wiki/installer.md | 24 +- 56 files changed, 1851 insertions(+), 666 deletions(-) create mode 100644 tests/fixtures/tui/plan-details-120x40.txt create mode 100644 tests/fixtures/tui/plan-details-40x12.txt create mode 100644 tests/fixtures/tui/plan-details-40x15.txt create mode 100644 tests/fixtures/tui/plan-details-80x24.txt create mode 100644 tests/fixtures/tui/result-details-120x40.txt create mode 100644 tests/fixtures/tui/result-details-40x12.txt create mode 100644 tests/fixtures/tui/result-details-40x15.txt create mode 100644 tests/fixtures/tui/result-details-80x24.txt diff --git a/install.ps1 b/install.ps1 index 087b4755c..5d08082f3 100644 --- a/install.ps1 +++ b/install.ps1 @@ -16,7 +16,7 @@ # and Invoke-WebRequest throws on a cut transfer before the hash is read: # the site's build rewrites this line there (scripts/sitebootstrap.py). $mismatchAdvice = "The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that." - $defaultInstallSha256 = "00376e0108c51fc9dbd27470080028be84251b1aa8d7bdfe28db3a71b2eae29e" + $defaultInstallSha256 = "d07c90a00f5bab9c583c34a9a1413bed5625542e7c88fed7bd9bab0020e9e637" # The pin above refuses any changed byte: this cap only stops a body that # cannot be the installer (a sign-in portal's page) before it is hashed. $maximumInstallerBytes = 8MB diff --git a/install.py b/install.py index 5d50497f8..6f1431495 100644 --- a/install.py +++ b/install.py @@ -6875,12 +6875,15 @@ def _report_outcome( say(next_step_words(platform_of or {}, paths)) +NEXT_ON_CARD = "Next: put the card back in the device and start a game." + + def next_step_words(platform_of: dict[Path, str], paths: list[Path]) -> str: """The step after an install that ended well: a card goes back in its device, a setup on this machine is started.""" setups = [(platform_of.get(path, ""), path) for path in paths] if setups and all(plat and on_its_card(plat, path) for plat, path in setups): - return "Next: put the card back in the device and start a game." + return NEXT_ON_CARD names = list(dict.fromkeys(detected_os(plat, path) or display_name(plat) for plat, path in setups if plat)) if len(names) == 1: @@ -6944,7 +6947,7 @@ def _check_fetch_line(fetch: int, beside: str, lacking: int = 0) -> str: f"internet, which {offline_named()} does not use. {_offline_remedy()}") # Why nothing is lost goes with the details: the remedy is the line. return (" Run the same command without --check to fetch them." - + (f" A wrong copy is replaced, and the one in place kept in {BACKUP_DIR} " + + (f"\n A wrong copy is replaced, and the one in place kept in {BACKUP_DIR} " f"beside {beside}." if OUTPUT.verbose else "")) @@ -16209,15 +16212,14 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None: # The count and the folder by default, each file with # --verbose: 20 paths hid the line saying what to do. print(f"\n {_plural(len(to_download) + trees_missing, 'file')} " - + ("not in place" if offline or LOCAL.pack is not None - else "to download") + (":" if OUTPUT.verbose else ".")) + + ("not in place." if offline or LOCAL.pack is not None + else "to download.")) for line in check_lines(missing, mismatched, files, manifest, bios_path, args.verbose, up_to_date, bios_index, copies): detail(line) for line in unreadable_lines(unread, args.verbose): print(line) - if not OUTPUT.verbose: - print(f" BIOS folder: {shown_path(bios_path)}") + print(f" BIOS folder: {shown_path(bios_path)}") # The data files need the internet too: offline, "8164 files # need the internet" stood under "10805 files not in place". trees_fetched = trees_missing if LOCAL.pack is None else 0 @@ -17196,6 +17198,8 @@ class TuiLine(str): # Whether the command it holds is typed into PowerShell, from the # Invocation that made it: its line ends follow its words. powershell: bool | None = None + # Shown on the Details screen, not on the screen it explains. + detail = False def _styled(text: str, style: str = "") -> TuiLine: @@ -17204,6 +17208,30 @@ def _styled(text: str, style: str = "") -> TuiLine: return line +def _detail(text: str, style: str = "") -> TuiLine: + """A line of the Details screen: an explanation, a list, a reason.""" + line = _styled(text, style) + line.detail = True + return line + + +def _details(lines: Iterable[str]) -> list[TuiLine]: + """lines as Details lines, each keeping how it is drawn.""" + marked = [] + for line in lines: + copy = TuiLine(str(line)) + for name in ("style", "mark", "command", "powershell"): + if hasattr(line, name): + setattr(copy, name, getattr(line, name)) + copy.detail = True + marked.append(copy) + return marked + + +def _is_detail(line: object) -> bool: + return bool(getattr(line, "detail", False)) + + def _command_line(text: str, hint: Invocation) -> TuiLine: """A line holding a command hint made, wrapped with hint's shell.""" line = _styled(text, "command") @@ -17504,6 +17532,9 @@ class TuiState: self.installed_only: bool = False self.jobs: int = 8 self.passthrough: list = [] + # Whether Details were opened on the result: the terminal keeps + # them after Exit too. + self.details_seen = False # The install. self.download: dict | None = None self.progress: dict | None = None @@ -18104,7 +18135,7 @@ class TuiRow(NamedTuple): # Screens that scroll text instead of listing rows. -_PAGERS = ("preview", "command", "result", "misplaced", "unreadable", "games") +_PAGERS = ("preview", "command", "result", "misplaced", "unreadable", "games", "details") _CHECKLISTS = ("systems", "cores") @@ -18483,9 +18514,10 @@ def _plan_rows(state: TuiState) -> list[TuiRow]: rows = [TuiRow("systems", TUI_SYSTEMS_ROW)] game_data = _game_data_row(state) return rows + ([game_data] if game_data is not None else []) + [ - TuiRow("options", "Options"), TuiRow("quit", "Quit")] + *_details_row(state), TuiRow("options", "Options"), TuiRow("quit", "Quit")] if not (_needed(check) if check else 0) and not check.get("data_missing"): - return [TuiRow("close", "Close"), *_games_rows(state), TuiRow("options", "Options")] + return [TuiRow("close", "Close"), *_games_rows(state), *_details_row(state), + TuiRow("options", "Options")] # The size the pack can give: "Install 6.6 GB" from a pack holding # none of the files. lacking = set(_tui_pack_lacks(state, [event["dest"] for event in state.files])) @@ -18542,7 +18574,18 @@ def _plan_rows(state: TuiState) -> list[TuiRow]: rows.append(TuiRow("misplaced", "Show the files in the wrong place")) if state.unreadable: rows.append(TuiRow("unreadable", "Show the files that could not be read")) - return rows + [TuiRow("options", "Options"), TuiRow("quit", "Quit")] + return rows + [*_details_row(state), TuiRow("options", "Options"), TuiRow("quit", "Quit")] + + +# The plan's explanations, counts and reasons, one press away: a pad has +# no d key. +TUI_DETAILS_ROW = TuiRow("details", "Details") + + +def _details_row(state: TuiState) -> list[TuiRow]: + """The Details row, where the plan leaves lines out: --verbose shows + them all on the plan itself.""" + return [] if tui_verbose(state) else [TUI_DETAILS_ROW] def games_where(state: TuiState) -> str: @@ -18604,11 +18647,11 @@ def games_plan_words(state: TuiState) -> list[str]: f"{', '.join(region_title(str(r)) for r in row['regions'])}" for row in games.get("found") or [] if row.get("regions")] if narrowed: - words.append(f"One region where the games prove it: {'; '.join(narrowed)}.") + words.append(_detail(f"One region where the games prove it: {'; '.join(narrowed)}.")) fallback = len(games.get("fallback") or []) if fallback: - words.append(f"{agree(fallback, 'game gets', 'games get')} every BIOS of " - f"{'its' if fallback == 1 else 'their'} system: Show the games.") + words.append(_detail(f"{agree(fallback, 'game gets', 'games get')} every BIOS of " + f"{'its' if fallback == 1 else 'their'} system: Show the games.")) return words @@ -19495,6 +19538,8 @@ def _tui_folder_facts(state: TuiState) -> dict: def _activate(state: TuiState, row: TuiRow) -> list[tuple]: screen, action = state.screen, row.action + if action == "details": + return _open_details(state) if action == "filter": only = _only_match(state) if only is not None: @@ -20438,6 +20483,10 @@ def _pager_key(state: TuiState, key: TuiKey) -> list[tuple]: elif name in ("enter", "esc", "backspace") or char == " ": if screen == "result": return tui_quit(state) + if screen == "details": + # Never _back: a run counting under the plan goes on. + state.stack.pop() + return [] return _back(state) state.focus[screen] = max(0, min(top, _pager_last(state, _pager_items(state)))) return [] @@ -20517,6 +20566,11 @@ def tui_update(state: TuiState, key: TuiKey) -> list[tuple]: state.focus["error_text"] = max(0, state.focus.get("error_text", 0) + (step if key.name == "pgdn" else -step)) return [] + if char == "d" and screen in ("plan", "confirm", "result") and not ( + screen == "confirm" and (state.running or state.dry is None)): + return _open_details(state) + if screen == "result" and not rows and (char == "o" or key.name == "tab"): + return _open_details(state) if screen in _PAGERS and not rows: return _pager_key(state, key) if not rows: @@ -21173,7 +21227,7 @@ _ROW_VERBS = { "unreadable": "Show", "exit": "Exit", "addapp": "Put it on the card", "cardsystem": "Choose", "rescan": "Look again", "elsewhere": "Choose", "drive": "Choose", "recheck": "Check again", "gamedata": "Change", "share": "Choose", "morecores": "Show", - "games": "Change", "startonly": "Change", "gameslist": "Show", + "games": "Change", "startonly": "Change", "gameslist": "Show", "details": "Show", } @@ -21564,7 +21618,7 @@ def _plan_lines(check: dict, dest: Path | None, state: TuiState) -> list: if found_in: # Right under the folder it names: after the save lines it read as # naming them. - lines.append(_styled(f"Named by {_short_path(Path(found_in[0]), state.home)}", "path")) + lines.append(_detail(f"Named by {_short_path(Path(found_in[0]), state.home)}", "path")) if state.facts.get("writable") is False: # The remedy itself comes below, after the counts. lines += cannot_write_words(dest, state.platform, tui_hint(state), @@ -21578,27 +21632,27 @@ def _plan_lines(check: dict, dest: Path | None, state: TuiState) -> list: counts = (f"{check['present']} in place, {check['missing'] + data} missing, " f"{_plural(wrong, 'wrong copy')}") # A first install's missing files are its normal state, not a warning. - lines.append(_styled(counts, "quiet") if not check["present"] and not wrong else counts) + lines.append(_detail(counts, "quiet" if not check["present"] and not wrong else "")) # The backup line goes right under the count it explains, before the # pack and copy split: at 40x12 and 40x15 it came after it, and was cut. count_at = len(lines) if copied and fetch and LOCAL.pack is not None: - lines.append(f"{fetch} from the pack, {len(copied)} copied from this machine") + lines.append(_detail(f"{fetch} from the pack, {len(copied)} copied from this machine")) elif copied and fetch and not offline: # 47 to download above 49 missing and 1 wrong copy: the 3 found on # this machine are the difference, on a line of its own ("0 wrong # copies: 2 of them" read as two of the zero). Offline the headline # says it: "3 downloaded" sat under "3 need the internet". - lines.append(f"{need} to install: {len(copied)} copied from this machine, " - f"{fetch} downloaded") + lines.append(_detail(f"{need} to install: {len(copied)} copied from this machine, " + f"{fetch} downloaded")) after_counts = len(lines) saves = (_choice_saves(state) if check is state.check else state.dry_saves if check is state.dry else None) saves_lines = _saves_lines(state, saves) - lines += [_styled(line, "path" if index else "") for index, line in enumerate(saves_lines)] + lines += [_detail(line, "path" if index else "") for index, line in enumerate(saves_lines)] free = state.facts.get("free") if free is not None: - lines.append(f"Free space: {format_size(free)}") + lines.append(_detail(f"Free space: {format_size(free)}")) if check["bytes_needed"] > free: lines.append(space_words(check["bytes_needed"], free, _on_its_card(state))) # The wrong copies something replaces: offline, those a folder copied @@ -21612,30 +21666,32 @@ def _plan_lines(check: dict, dest: Path | None, state: TuiState) -> list: if wrong_dests else wrong) misplaced = _tui_misplaced(state) if check is state.check else [] if misplaced: - lines.insert(after_counts, f"{_plural(len(misplaced), 'file')} " - f"{'is' if len(misplaced) == 1 else 'are'} in the wrong place, " - f"{'it' if len(misplaced) == 1 else 'they'} will be copied where the " - "emulators read " - f"{'it' if len(misplaced) == 1 else 'them'}, the " - f"{'copy' if len(misplaced) == 1 else 'copies'} left as " - f"{'it is' if len(misplaced) == 1 else 'they are'}.") + lines.insert(after_counts, _detail( + f"{_plural(len(misplaced), 'file')} " + f"{'is' if len(misplaced) == 1 else 'are'} in the wrong place, " + f"{'it' if len(misplaced) == 1 else 'they'} will be copied where the " + "emulators read " + f"{'it' if len(misplaced) == 1 else 'them'}, the " + f"{'copy' if len(misplaced) == 1 else 'copies'} left as " + f"{'it is' if len(misplaced) == 1 else 'they are'}.")) if backup: # With its subject: "They are replaced" sat lines under the count. # Not where nothing can be installed: nothing is replaced then. - lines.insert(count_at, (f"The {_plural(wrong, 'wrong copy')} " if backup == wrong - else f"{backup} of the {_plural(wrong, 'wrong copy')} ") - + f"{'is' if backup == 1 else 'are'} replaced, the old " - f"{'one' if backup == 1 else 'ones'} kept in a backup folder.") + lines.insert(count_at, _detail( + (f"The {_plural(wrong, 'wrong copy')} " if backup == wrong + else f"{backup} of the {_plural(wrong, 'wrong copy')} ") + + f"{'is' if backup == 1 else 'are'} replaced, the old " + f"{'one' if backup == 1 else 'ones'} kept in a backup folder.")) if state.facts.get("writable") is False and dest is not None: lines += _commands(state, write_remedy(dest, state.platform, tui_hint(state), state.pad not in TUI_PAD_ROUTES)) if check is state.check: - lines += _scan_lines(state) + lines += _details(_scan_lines(state)) if check.get("not_installable"): - lines += _unavailable_lines(state) + lines += _details(_unavailable_lines(state)) if check is state.check: - lines += _unplaced_lines(_choice_summary(state), state, - "Choose it in Options, Save folder (--save-dir).") + lines += _details(_unplaced_lines(_choice_summary(state), state, + "Choose it in Options, Save folder (--save-dir).")) if check is state.check and state.from_folders: # A folder copied from that holds none of them: the plan came back # the same, still saying to copy from a folder. @@ -22014,7 +22070,8 @@ def _choice_line(state: TuiState) -> list[str]: "count comes before the install."] -def _view_plan(state: TuiState, width: int, height: int) -> tuple: +def _plan_text(state: TuiState) -> list: + """Every line of the plan, the Details lines among them.""" check = state.check or {} lines = _plan_lines(check, state.dest, state) choice = _choice_line(state) @@ -22126,11 +22183,11 @@ def _view_plan(state: TuiState, width: int, height: int) -> tuple: if found and parts: parts = (f"Not in {', '.join(_last_name(str(folder)) for folder in found)}: " f"{parts}") - lines[at:at] = [*([state.card_note] if state.card_note + lines[at:at] = [*([_detail(state.card_note)] if state.card_note and state.card_note != state.status else []), *([f"{said[0].upper()}{said[1:]}."] if said else []), *([emptied_named] if emptied_named else []), *choice, - *([parts] if parts else []), *games_plan_words(state)] + *([_detail(parts)] if parts else []), *games_plan_words(state)] if state.version: # Before the free space, which gives way first: appended last, the # note was cut from the 40x12 plan with no sign. @@ -22140,7 +22197,7 @@ def _view_plan(state: TuiState, width: int, height: int) -> tuple: if state.board: free = next((index for index, line in enumerate(lines) if str(line).startswith("Free space:")), len(lines)) - lines.insert(free, state.board) + lines.insert(free, _detail(state.board)) if state.status: lines.append(state.status) if defined: @@ -22150,7 +22207,25 @@ def _view_plan(state: TuiState, width: int, height: int) -> tuple: # where the screen has no room. saves = next((index for index, line in enumerate(lines) if "'s save directory" in str(line)), len(lines)) - lines.insert(saves, defined) + lines.insert(saves, _detail(defined)) + return lines + + +def tui_verbose(state: TuiState) -> bool: + """Whether the screen was opened with --verbose: every line is shown + where it belongs, as before the Details screen held them.""" + return any(flag == "--verbose" for flag, _value in state.passthrough) + + +def _shown(state: TuiState, lines: list) -> list: + """The lines a screen shows: all with --verbose, else all but Details.""" + return list(lines) if tui_verbose(state) else [ + line for line in lines if not _is_detail(line)] + + +def _view_plan(state: TuiState, width: int, height: int) -> tuple: + check = state.check or {} + lines = _shown(state, _plan_text(state)) # A folder that does not fit is wrapped, as the first screen wraps it: # cut in its middle, the plan hid the part being checked before Install. # At 40 columns too, broken after a separator: cut there, it was spelled @@ -22442,7 +22517,9 @@ def _pager_items(state: TuiState) -> list: if state.screen == "games": return games_pager_lines(state) if state.screen == "result": - return tui_outcome(state)[1] + return _shown(state, tui_outcome(state)[1]) + if state.screen == "details": + return details_lines(state) if state.screen == "command": return ["The same choice without questions:", "", _command_line(tui_command(state), tui_hint(state))] @@ -22511,18 +22588,7 @@ def _view_confirm(state: TuiState, width: int, height: int) -> tuple: # Why this screen: the numbers above are counted again for the # systems and options chosen, the last look before anything is # written. - lines = _plan_lines(state.dry, state.dest, state) - # The kinds apart, as the plan counts them, under the folder. - data = state.dry.get("data_missing", 0) - parts, _defined = _kinds_lines(state, state.dry_files, data, - state.dry.get("data_bytes") if data else None) - if parts: - at = next((index + 1 for index, line in enumerate(lines) - if str(line).startswith(_FOLDER_LABEL)), len(lines)) - lines.insert(at, parts) - if any(row.action == "install" for row in tui_rows(state)): - lines.insert(0, "Counted again for these choices. Nothing is written before " - "Install.") + lines = _shown(state, _confirm_text(state)) if not any(row.action == "install" for row in tui_rows(state)) and state.dry is not None: # Back alone: one Back on the bar, and no word of an Install. Titled # for what it is: "Confirm" over nothing to confirm. @@ -22533,6 +22599,23 @@ def _view_confirm(state: TuiState, width: int, height: int) -> tuple: ("A/Enter Install", "B/Esc Back", "? Help")) +def _confirm_text(state: TuiState) -> list: + """Every line of Confirm, the Details lines among them.""" + lines = _plan_lines(state.dry or {}, state.dest, state) + # The kinds apart, as the plan counts them, under the folder. + data = (state.dry or {}).get("data_missing", 0) + parts, _defined = _kinds_lines(state, state.dry_files, data, + (state.dry or {}).get("data_bytes") if data else None) + if parts: + at = next((index + 1 for index, line in enumerate(lines) + if str(line).startswith(_FOLDER_LABEL)), len(lines)) + lines.insert(at, _detail(parts)) + if any(row.action == "install" for row in tui_rows(state)): + lines.insert(0, "Counted again for these choices.") + lines.insert(1, _detail("Nothing is written before Install.")) + return lines + + def _bar(share: float, width: int) -> str: room = max(4, width - 7) filled = int(share * room) @@ -22568,7 +22651,7 @@ def _view_installing(state: TuiState, width: int, height: int) -> tuple: else f"{stops[1]} stops. What is done stays done.") room = height - len(lines) - 1 failed = [item for item in reversed(state.finished) if not item[1]] - good = [item for item in reversed(state.finished) if item[1]] + good = [item for item in reversed(state.finished) if item[1]] if tui_verbose(state) else [] shown = (failed + good)[:max(0, room)] if shown: lines.append("") @@ -22778,13 +22861,13 @@ def tui_outcome(state: TuiState) -> tuple[str, list[str]]: apart = _tui_tally(state, [{"dest": dest, "size": 0} for dest in missing if dest not in wrong_dests]) if _tui_categories(state) and apart.bios and apart.games: - lines.append(f"Still missing: {installed_words(apart.bios, apart.games)}.") + lines.append(_detail(f"Still missing: {installed_words(apart.bios, apart.games)}.")) # Each folder spelled in full, as the result names its others. lines.append(_offline_remedy([shown_path(folder) for folder in state.from_folders])) ok = {dest for dest, good, _why in state.finished if good} if any(reason and dest in ok for dest, (_folder, reason) in state.local_dests.items()): # A fix copies: the misplaced files are the user's, never moved. - lines.append("The copies in the wrong place were left as they are.") + lines.append(_detail("The copies in the wrong place were left as they are.")) if _tui_categories(state) and title != "Stopped" and installed: # As the plan counted them, and as line mode ends, on every result: # the old card's said "6 files copied" and no kind. The data tree @@ -22792,14 +22875,14 @@ def tui_outcome(state: TuiState) -> tuple[str, list[str]]: done = _tui_tally(state, [{"dest": dest, "size": 0} for dest, good, _why in state.finished if good]) if done.files and not (title == "Done" and _one_kind(state, installed)): - lines.append("Installed: " + installed_words( - done.bios, done.games, max(0, installed - done.files)) + ".") + lines.append(_detail("Installed: " + installed_words( + done.bios, done.games, max(0, installed - done.files)) + ".")) # The folder the plan named: MinUI's Bios, not the card's root. lines.append(f"BIOS folder: {shown_path(_plan_folder(state, state.dest))}") if installed + up_to_date: # Spelled as the BIOS folder above it is, whole: "~/" beside a full # path was two spellings on one screen. - lines += _saves_lines(state, state.done_saves, whole=True) + lines += _details(_saves_lines(state, state.done_saves, whole=True)) if state.version: # Said again with the result, as line mode ends: the system's own # BIOS check may mark the files just put in place. @@ -22813,7 +22896,8 @@ def tui_outcome(state: TuiState) -> tuple[str, list[str]]: names = ", ".join(str(item.get("name")) for item in fallback[:3]) more = f" and {len(fallback) - 3} more" if len(fallback) > 3 else "" their = "its" if len(fallback) == 1 else "their" - lines.append(f"Not recognised, every BIOS of {their} system kept: {names}{more}.") + lines.append(_detail(f"Not recognised, every BIOS of {their} system kept: " + f"{names}{more}.")) if space: lines.append("Free some space on the card, then run again." if _on_its_card(state) else "Free some space, or run again and choose another folder.") @@ -22829,10 +22913,10 @@ def tui_outcome(state: TuiState) -> tuple[str, list[str]]: continue for dest in dests: if shown < 20: - lines.append(f" failed: {dest}" + (f" ({reason})" if reason else "")) + lines.append(_detail(f" failed: {dest}" + (f" ({reason})" if reason else ""))) shown += 1 if shown > 20: - lines.append(f" ... and {shown - 20} more") + lines.append(_detail(f" ... and {shown - 20} more")) if title == "Finished with errors": # What a rerun does, as line mode and the first install page say # it: the screen never did. @@ -22848,8 +22932,9 @@ def tui_outcome(state: TuiState) -> tuple[str, list[str]]: if expected > landed and not left and title != "Stopped" and summary: # The data files the plan counted, never named on a result that # counted the BIOS files alone. - lines.append(f"{_plural(expected - landed, 'data file')} not installed" - + (f": not in {LOCAL.pack.name}." if LOCAL.pack is not None else ".")) + lines.append(_detail(f"{_plural(expected - landed, 'data file')} not installed" + + (f": not in {LOCAL.pack.name}." if LOCAL.pack is not None + else "."))) if state.dest is not None and any(failure["reason"] == NOT_WRITABLE for failure in failed): # The plan's own advice: the result offered nothing after 22 files @@ -22869,27 +22954,38 @@ def tui_outcome(state: TuiState) -> tuple[str, list[str]]: lines.append(f"The files it replaced are kept in {kept['folder']}") if typed: # Broken between its words only, never inside one (_wrap). - lines.append(_command_line(f"To put them back: {run.launcher()} --restore " - f"{run.word(str(kept['folder']))}", run)) + lines += _details([_command_line(f"To put them back: {run.launcher()} --restore " + f"{run.word(str(kept['folder']))}", run)]) if summary and not summary.get("interrupted") and installed + up_to_date: - lines += _unavailable_lines(state) + lines += _details(_unavailable_lines(state)) for group in summary.get("left_out") or []: - lines.append(f"{left_out_words(group)}.") - lines += _unplaced_lines(summary, state) + lines.append(_detail(f"{left_out_words(group)}.")) + lines += _details(_unplaced_lines(summary, state)) lines += _tui_app_lines(state) + if title == "Done" and not (state.platform == "romm" and installed): + # Last of what the result says by default: RomM's scan is its step. + lines.append(tui_next_words(state)) if typed: - lines += ["Same choice without questions:", - _command_line(f" {tui_command(state)}", tui_hint(state))] + lines += _details(["Same choice without questions:", + _command_line(f" {tui_command(state)}", tui_hint(state))]) if tui_keeps_log(state): - lines.append(f"Details: {state.log}") + lines.append(f"Log: {state.log}") if state.mouse and typed: # A drag over the command selected nothing: the terminal sends the # press as a report. Said where it is read. - lines.append(_styled(TUI_RESULT_AGAIN if state.os_type == "android" + lines.append(_detail(TUI_RESULT_AGAIN if state.os_type == "android" else TUI_RESULT_COPY, "dim")) return title, lines +def tui_next_words(state: TuiState) -> str: + """The step after an install the result says went well.""" + if _on_its_card(state): + return NEXT_ON_CARD + name = detected_os(state.platform, state.dest) if state.dest is not None else "" + return f"Next: start {name or display_name(state.platform, state.manifest)} and play." + + def _dest_error_outcome(state: TuiState, installed: int) -> tuple[str, list[str]]: """The result of a run whose BIOS folder could not be created: that reason for every file, and its remedy. It said "22 files not fetched @@ -22908,10 +23004,10 @@ def _dest_error_outcome(state: TuiState, installed: int) -> tuple[str, list[str] lines.append("Run it again and choose another folder.") lines += _commands(state, remedy) if state.pad not in TUI_PAD_ROUTES: - lines += ["Same choice without questions:", - _command_line(f" {tui_command(state)}", tui_hint(state))] + lines += _details(["Same choice without questions:", + _command_line(f" {tui_command(state)}", tui_hint(state))]) if tui_keeps_log(state): - lines.append(f"Details: {state.log}") + lines.append(f"Log: {state.log}") return ("Nothing installed" if not installed else "Finished with errors"), lines @@ -22957,6 +23053,7 @@ def tui_keeps_log(state: TuiState) -> bool: def _view_result(state: TuiState, width: int, height: int) -> tuple: title, lines = tui_outcome(state) + lines = _shown(state, lines) # The outcome in bold, its counts in their roles: it led a list of # lines drawn alike. lines[0] = _styled(lines[0], "title") @@ -22971,7 +23068,7 @@ def _view_result(state: TuiState, width: int, height: int) -> tuple: if state.app_running: return (title, _pager(state, width, height, lines), ("Writing to the card...",)) return (title, _pager(state, width, height, lines), - ("A/Enter Exit", *_scroll(state, lines, width, height))) + ("A/Enter Exit", "Y/o Details", *_scroll(state, lines, width, height))) def _view_error(state: TuiState, width: int, height: int) -> tuple: @@ -23006,6 +23103,36 @@ def _view_quit(state: TuiState, width: int, height: int) -> tuple: rows), hint) +def details_lines(state: TuiState) -> list: + """What the screen under Details leaves out: its explanations, lists + and reasons.""" + if len(state.stack) < 2: + return ["Nothing more to say here."] + # Read as the screen under it reads itself: its rows, its words. + top = state.stack.pop() + try: + under = state.screen + lines = (_plan_text(state) if under == "plan" + else _confirm_text(state) if under == "confirm" + else tui_outcome(state)[1] if under == "result" else []) + finally: + state.stack.append(top) + return [line for line in lines if _is_detail(line)] or ["Nothing more to say here."] + + +def _view_details(state: TuiState, width: int, height: int) -> tuple: + items = _pager_items(state) + return ("Details", _pager(state, width, height, items), + ("A/Enter Back", *_scroll(state, items, width, height))) + + +def _open_details(state: TuiState) -> list[tuple]: + if state.screen == "result": + # Looked at, they are said again in the terminal after Exit. + state.details_seen = True + return _push(state, "details") + + _TUI_VIEWS: dict[str, Callable[[TuiState, int, int], tuple]] = { "setup": _view_setup, "platforms": _view_platforms, "folder": _view_folder, "browse": _view_browse, "path": _view_path, "create": _view_create, @@ -23014,7 +23141,7 @@ _TUI_VIEWS: dict[str, Callable[[TuiState, int, int], tuple]] = { "preview": _view_preview, "command": _view_command, "confirm": _view_confirm, "installing": _view_installing, "result": _view_result, "error": _view_error, "quit": _view_quit, "cardroot": _view_cardroot, "misplaced": _view_misplaced, - "unreadable": _view_unreadable, "games": _view_games, + "unreadable": _view_unreadable, "games": _view_games, "details": _view_details, } @@ -23078,6 +23205,10 @@ def _help_lines(state: TuiState) -> list[tuple[str, str]]: keys.append(("Left/Right", "Change a value")) if screen in ("plan", "systems", "confirm"): keys.append((names["options"], "Options")) + if screen in ("plan", "confirm"): + keys.append(("d", "Details")) + elif screen == "result" and not tui_rows(state): + keys.append((f"{names['options']}, d" if names["options"] else "d", "Details")) # The result's bar calls B Exit: the help called it Quit. back = "Exit" if screen == "result" else "Quit" if len(state.stack) == 1 else "Back" keys += [(names["back"], back), ("q, Ctrl-C", "Quit"), *kill, *_route_extras(state), @@ -23156,7 +23287,7 @@ def _view_help(state: TuiState, width: int, height: int) -> tuple: # Cut from its end at 40x12, the help lost Quit and This help with no # sign: what a list's keys also say elsewhere goes first. for spare in ("First, last", "All, none", "extra", "Filter by setup or device name", - "Filter", "Options", "This help", "gap", "definitions"): + "Filter", "Options", "Details", "This help", "gap", "definitions"): if (len(drawn(keys)) + len(extra) + len(defined) + len(_text_lines(more, width)) <= height): break @@ -23975,15 +24106,15 @@ def _said_lines(state: TuiState) -> list[str]: def _closing_lines(state: TuiState) -> list[str]: - if state.screen != "result" and state.download is not None: + if state.screen not in ("result", "details") and state.download is not None: # An install ran: what it wrote is said, whatever ended it. title, lines = tui_outcome(state) - return [f"RetroBIOS: {title}", *_terminal_words(lines)] + return [f"RetroBIOS: {title}", *_terminal_words(_farewell_shown(state, lines))] if state.screen == "crashed": return [f"RetroBIOS stopped on an unexpected error. What it was is in {state.log}."] - if state.screen == "result": + if state.screen == "result" or (state.screen == "details" and "result" in state.stack): title, lines = tui_outcome(state) - return [f"RetroBIOS: {title}", *_terminal_words(lines)] + return [f"RetroBIOS: {title}", *_terminal_words(_farewell_shown(state, lines))] if state.screen == "error": return [f"RetroBIOS: {state.error_title or 'something went wrong'}", *(line.replace("then choose Try again", "then run the installer again") @@ -24012,6 +24143,12 @@ TUI_SAVE_REMEDY = "Choose it in Options, Save folder (--save-dir), next time." LINE_SAVE_REMEDY = "Name it with --save-dir next time." +def _farewell_shown(state: TuiState, lines: list) -> list: + """The result as the terminal keeps it: Details too once they were + opened, as the result's copy hint says.""" + return list(lines) if state.details_seen else _shown(state, lines) + + def _terminal_words(lines: list[str]) -> list[str]: """The result's lines as the terminal prints them after the screen.""" return [line.replace(TUI_SAVE_REMEDY, LINE_SAVE_REMEDY) for line in lines diff --git a/install.sh b/install.sh index 36aaf3311..4c22d6cb4 100755 --- a/install.sh +++ b/install.sh @@ -23,7 +23,7 @@ DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/ins # curl or wget stop on a cut transfer before the hash is read: the site's # build rewrites this line there (scripts/sitebootstrap.py). MISMATCH_ADVICE="The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that." -DEFAULT_INSTALL_SHA256="00376e0108c51fc9dbd27470080028be84251b1aa8d7bdfe28db3a71b2eae29e" +DEFAULT_INSTALL_SHA256="d07c90a00f5bab9c583c34a9a1413bed5625542e7c88fed7bd9bab0020e9e637" # The pin above refuses any changed byte: this cap only stops a body that # cannot be the installer (a sign-in portal's page) before it is hashed. MAX_INSTALLER_BYTES=8388608 diff --git a/install/launchers/index.json b/install/launchers/index.json index c056dc24c..4b00af4b4 100644 --- a/install/launchers/index.json +++ b/install/launchers/index.json @@ -27,8 +27,8 @@ { "dest": "roms/ports/retrobios/install.py", "repo_path": "install.py", - "size": 1135666, - "sha256": "00376e0108c51fc9dbd27470080028be84251b1aa8d7bdfe28db3a71b2eae29e", + "size": 1141160, + "sha256": "d07c90a00f5bab9c583c34a9a1413bed5625542e7c88fed7bd9bab0020e9e637", "executable": false }, { @@ -71,8 +71,8 @@ "muos": { "archive": { "dest": "ARCHIVE/RetroBIOS.muxapp", - "size": 1189291, - "sha256": "c56ce912e436173542905c89c1aee7de025f93bea5df130ab51e589c071f6369" + "size": 1194785, + "sha256": "344b9bb17095fef0ae3dfcee82f7144075b0c388033337552e37a2910f473dc9" }, "members": [ { @@ -92,8 +92,8 @@ { "name": "RetroBIOS/install.py", "repo_path": "install.py", - "size": 1135666, - "sha256": "00376e0108c51fc9dbd27470080028be84251b1aa8d7bdfe28db3a71b2eae29e", + "size": 1141160, + "sha256": "d07c90a00f5bab9c583c34a9a1413bed5625542e7c88fed7bd9bab0020e9e637", "executable": false }, { @@ -166,8 +166,8 @@ { "dest": ".config/modules/retrobios/install.py", "repo_path": "install.py", - "size": 1135666, - "sha256": "00376e0108c51fc9dbd27470080028be84251b1aa8d7bdfe28db3a71b2eae29e", + "size": 1141160, + "sha256": "d07c90a00f5bab9c583c34a9a1413bed5625542e7c88fed7bd9bab0020e9e637", "executable": false }, { diff --git a/scripts/generate_installer_doc.py b/scripts/generate_installer_doc.py index 7baf85733..5a1b795e8 100644 --- a/scripts/generate_installer_doc.py +++ b/scripts/generate_installer_doc.py @@ -604,7 +604,7 @@ def _refused_lines(text: str) -> list[str]: """The files a check flags, each with its reason and where its cores read it.""" lines = text.splitlines() start = next((i for i, line in enumerate(lines) - if re.fullmatch(r" \d+ files? [a-z ]+:", line)), None) + if re.fullmatch(r" \d+ files? [a-z ]+\.", line)), None) if start is None: raise SampleFailed("the check printed no files not in place") end = max(i for i, line in enumerate(lines) if line.lstrip().startswith("read by ")) diff --git a/tests/fixtures/tui/colour-120x40.txt b/tests/fixtures/tui/colour-120x40.txt index 536322f7f..66389a8c2 100644 --- a/tests/fixtures/tui/colour-120x40.txt +++ b/tests/fixtures/tui/colour-120x40.txt @@ -331,13 +331,11 @@ ^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m - ^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m - The ^[[0;33m1 wrong copy^[[0m is replaced, the old one kept in a backup folder. - Free space: 50.0 GB ^[[0;7;35m > Install^[[0m Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit @@ -363,6 +361,8 @@ + + @@ -372,11 +372,9 @@ ^[[0;1m ^[[0;1;32mEvery file on the list is in place^[[0m BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m - ^[[0;32m5 in place^[[0m, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, the old one kept in a backup folder. - Free space: 50.0 GB ^[[0;7;35m > Close^[[0m + Details Options @@ -404,6 +402,8 @@ + + @@ -657,11 +657,9 @@ === confirm ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Confirm^[[0m - Counted again for these choices. Nothing is written before Install. + Counted again for these choices. ^[[0;1m ^[[0;1;35m1^[[0;1m file to download, ^[[0;1;35m16.0 KB^[[0m BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB ^[[0;7;35m > Install^[[0m Back @@ -691,6 +689,8 @@ + + @@ -705,7 +705,7 @@ B, Ctrl-C or Select+Start stops. What is done stays done. ^[[0;1;31mFAILED^[[0m scph5500.bin (HTTP 404) -^[[0;32m ok^[[0m gba_bios.bin + @@ -741,14 +741,9 @@ ^[[0;1m ^[[0;1;32m3 installed^[[0;1m, ^[[0;1;31m1 failed^[[0;1m.^[[0m BIOS folder: ^[[0;1m/home/user/.config/retroarch/system^[[0m - ^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 - To put them back: python3 install.py \ - --restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 - Same choice without questions: - python3 install.py --platform retroarch --dest /home/user/.config/retroarch/system - Details: /tmp/retrobios-x/install.log + Log: /tmp/retrobios-x/install.log @@ -776,7 +771,12 @@ - ^[[0;1;35mA/Enter^[[0m Exit + + + + + + ^[[0;1;35mA/Enter^[[0m Exit ^[[0;2mY/o^[[0m Details === error ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: ^[[0;1;31mSomething went wrong^[[0m @@ -865,6 +865,7 @@ Up/Down, k/j Move A/Enter, Start Install Y, o, Tab Options + d Details B/Esc, Backspace Back q, Ctrl-C Quit ?, F1 This help @@ -896,7 +897,6 @@ - Any key closes this help @@ -906,11 +906,6 @@ ^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m For the 412 games on this card. - One region where the games prove it: nintendo-gba Europe. - 2 games get every BIOS of their system: Show the games. - ^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m - The ^[[0;33m1 wrong copy^[[0m is replaced, the old one kept in a backup folder. - Free space: 50.0 GB ^[[0;7;35m > Install^[[0m For the games on this card: yes 412 games @@ -918,6 +913,7 @@ Show the games Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit @@ -936,6 +932,10 @@ + + + + @@ -969,6 +969,88 @@ + + + + + + + + + + + + + ^[[0;1;35mA/Enter^[[0m Back +=== plan-details +^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m + + ^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m + The ^[[0;33m1 wrong copy^[[0m is replaced, the old one kept in a backup folder. + Free space: 50.0 GB + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ^[[0;1;35mA/Enter^[[0m Back +=== result-details +^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m + + ^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404) + To put them back: python3 install.py \ + --restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 + Same choice without questions: + python3 install.py --platform retroarch --dest /home/user/.config/retroarch/system + + + + + + + + + + + + + + + + + + + + diff --git a/tests/fixtures/tui/colour-40x12.txt b/tests/fixtures/tui/colour-40x12.txt index ce9ed9559..cfdbdf301 100644 --- a/tests/fixtures/tui/colour-40x12.txt +++ b/tests/fixtures/tui/colour-40x12.txt @@ -108,10 +108,10 @@ ^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m - ^[[0;33m1 wrong copy^[[0m: backed up, replaced. ^[[0;7;35m > Install^[[0m Choose systems Copy from an old card or a folder + Details Options Quit ^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help @@ -121,12 +121,12 @@ ^[[0;1m ^[[0;1;32mEvery file on the list is in place^[[0m BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m - ^[[0;32m5 in place^[[0m, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB + ^[[0;7;35m > Close^[[0m + Details Options + + ^[[0;1;35mA^[[0m Close ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help === systems ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Choose systems^[[0m @@ -210,14 +210,14 @@ ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Confirm^[[0m Counted again for these choices. - Nothing is written before Install. ^[[0;1m ^[[0;1;35m1^[[0;1m file to download, ^[[0;1;35m16.0 KB^[[0m BIOS folder: ^[[0;1m~/.co.../retroarch/system^[[0m - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB ^[[0;7;35m > Install^[[0m Back + + + ^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2m?^[[0m Help === installing ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Installing^[[0m @@ -230,7 +230,7 @@ is done stays done. ^[[0;1;31mFAILED^[[0m scph5500.bin (HTTP 404) -^[[0;32m ok^[[0m gba_bios.bin + ^[[0;1;35mB^[[0m Stop ^[[0;2m?^[[0m Help === result ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: ^[[0;1;31mFinished with errors^[[0m @@ -238,13 +238,13 @@ ^[[0;1m ^[[0;1;32m3 installed^[[0;1m, ^[[0;1;31m1 failed^[[0;1m.^[[0m BIOS folder: ^[[0;1m/home/user/.config/retroarch/system^[[0m - ^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/ retrobios-backup/2026-10-23_1200 -^[[0;2m 1-8 of 17^[[0m - ^[[0;1;35mA^[[0m Exit ^[[0;2m^v^[[0m Scroll + Log: /tmp/retrobios-x/install.log + + ^[[0;1;35mA^[[0m Exit ^[[0;2mY^[[0m Details === error ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: ^[[0;1;31mSomething went wrong^[[0m @@ -277,12 +277,12 @@ Up/Down, k/j Move A/Enter, Start Install Y, o, Tab Options + d Details B/Esc, Backspace Back q, Ctrl-C Quit ?, F1 This help - BIOS folder: - ^[[0;1m/home/user/.config/retroarch/system^[[0m + Any key closes this help === plan-games ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m @@ -295,7 +295,7 @@ For the games on this card: yes 412 Only what starts: no Show the games -^[[0;2m 1-4 of 8^[[0m +^[[0;2m 1-4 of 9^[[0m ^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help === games ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Games on this card^[[0m @@ -310,3 +310,29 @@ ^[[0;2m 1-5 of 9^[[0m ^[[0;1;35mA^[[0m Back ^[[0;2m^v^[[0m Scroll +=== plan-details +^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m + + ^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m + The ^[[0;33m1 wrong copy^[[0m is replaced, the old + one kept in a backup folder. + Free space: 50.0 GB + + + + + + ^[[0;1;35mA^[[0m Back +=== result-details +^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m + + ^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404) + To put them back: python3 install.py \ + --restore .../2026-10-23_1200 +^[[0;2m Shortened to fit this window.^[[0m + Same choice without questions: + python3 install.py \ + --platform retroarch \ + --dest .../retroarch/system +^[[0;2m Shortened to fit this window.^[[0m + ^[[0;1;35mA^[[0m Back diff --git a/tests/fixtures/tui/colour-40x15.txt b/tests/fixtures/tui/colour-40x15.txt index 8b56ed9b5..4772e545b 100644 --- a/tests/fixtures/tui/colour-40x15.txt +++ b/tests/fixtures/tui/colour-40x15.txt @@ -132,15 +132,15 @@ ^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m - ^[[0;33m1 wrong copy^[[0m: backed up, replaced. - ^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m - Free space: 50.0 GB ^[[0;7;35m > Install^[[0m Choose systems Copy from an old card or a folder + Details Options Quit + + ^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help === plan-in-place ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m @@ -148,15 +148,15 @@ ^[[0;1m ^[[0;1;32mEvery file on the list is in place^[[0m BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m - ^[[0;32m5 in place^[[0m, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB ^[[0;7;35m > Close^[[0m + Details Options + + + ^[[0;1;35mA^[[0m Close ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help === systems ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Choose systems^[[0m @@ -258,17 +258,17 @@ ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Confirm^[[0m Counted again for these choices. - Nothing is written before Install. ^[[0;1m ^[[0;1;35m1^[[0;1m file to download, ^[[0;1;35m16.0 KB^[[0m BIOS folder: ^[[0;1m~/.co.../retroarch/system^[[0m - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB ^[[0;7;35m > Install^[[0m Back + + + ^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2m?^[[0m Help === installing ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Installing^[[0m @@ -281,7 +281,7 @@ is done stays done. ^[[0;1;31mFAILED^[[0m scph5500.bin (HTTP 404) -^[[0;32m ok^[[0m gba_bios.bin + @@ -292,16 +292,16 @@ ^[[0;1m ^[[0;1;32m3 installed^[[0;1m, ^[[0;1;31m1 failed^[[0;1m.^[[0m BIOS folder: ^[[0;1m/home/user/.config/retroarch/system^[[0m - ^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/ retrobios-backup/2026-10-23_1200 - To put them back: python3 install.py \ - --restore .../2026-10-23_1200 -^[[0;2m Shortened to fit this window.^[[0m -^[[0;2m 1-11 of 17^[[0m - ^[[0;1;35mA^[[0m Exit ^[[0;2m^v^[[0m Scroll + Log: /tmp/retrobios-x/install.log + + + + + ^[[0;1;35mA^[[0m Exit ^[[0;2mY^[[0m Details === error ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: ^[[0;1;31mSomething went wrong^[[0m @@ -340,6 +340,7 @@ Up/Down, k/j Move A/Enter, Start Install Y, o, Tab Options + d Details B/Esc, Backspace Back q, Ctrl-C Quit ?, F1 This help @@ -348,7 +349,6 @@ ^[[0;1m/home/user/.config/retroarch/system^[[0m - Any key closes this help === plan-games ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m @@ -356,13 +356,13 @@ ^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m - For the 412 games on this card. ^[[0;7;35m > Install^[[0m For the games on this card: yes 412 Only what starts: no Show the games Choose systems Copy from an old card or a folder + Details Options Quit ^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help @@ -381,4 +381,36 @@ that they start: GBA/demo.gba: not recognised GBA/hack.gba: not recognised + ^[[0;1;35mA^[[0m Back +=== plan-details +^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m + + ^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m + The ^[[0;33m1 wrong copy^[[0m is replaced, the old + one kept in a backup folder. + Free space: 50.0 GB + + + + + + + + + ^[[0;1;35mA^[[0m Back +=== result-details +^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m + + ^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404) + To put them back: python3 install.py \ + --restore .../2026-10-23_1200 +^[[0;2m Shortened to fit this window.^[[0m + Same choice without questions: + python3 install.py \ + --platform retroarch \ + --dest .../retroarch/system +^[[0;2m Shortened to fit this window.^[[0m + + + ^[[0;1;35mA^[[0m Back diff --git a/tests/fixtures/tui/colour-80x24.txt b/tests/fixtures/tui/colour-80x24.txt index 1fbde9a63..f86488285 100644 --- a/tests/fixtures/tui/colour-80x24.txt +++ b/tests/fixtures/tui/colour-80x24.txt @@ -203,13 +203,11 @@ ^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m - ^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m - The ^[[0;33m1 wrong copy^[[0m is replaced, the old one kept in a backup folder. - Free space: 50.0 GB ^[[0;7;35m > Install^[[0m Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit @@ -222,17 +220,17 @@ + + ^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Options ^[[0;2m?^[[0m Help === plan-in-place ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m ^[[0;1m ^[[0;1;32mEvery file on the list is in place^[[0m BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m - ^[[0;32m5 in place^[[0m, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, the old one kept in a backup folder. - Free space: 50.0 GB ^[[0;7;35m > Close^[[0m + Details Options @@ -247,6 +245,8 @@ + + ^[[0;1;35mA/Enter^[[0m Close ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Options ^[[0;2m?^[[0m Help === systems ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Choose systems^[[0m @@ -401,11 +401,9 @@ === confirm ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Confirm^[[0m - Counted again for these choices. Nothing is written before Install. + Counted again for these choices. ^[[0;1m ^[[0;1;35m1^[[0;1m file to download, ^[[0;1;35m16.0 KB^[[0m BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB ^[[0;7;35m > Install^[[0m Back @@ -422,6 +420,8 @@ + + ^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2m?^[[0m Help === installing ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Installing^[[0m @@ -433,7 +433,7 @@ B, Ctrl-C or Select+Start stops. What is done stays done. ^[[0;1;31mFAILED^[[0m scph5500.bin (HTTP 404) -^[[0;32m ok^[[0m gba_bios.bin + @@ -453,16 +453,10 @@ ^[[0;1m ^[[0;1;32m3 installed^[[0;1m, ^[[0;1;31m1 failed^[[0;1m.^[[0m BIOS folder: ^[[0;1m/home/user/.config/retroarch/system^[[0m - ^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 - To put them back: python3 install.py \ - --restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 - Same choice without questions: - python3 install.py --platform retroarch \ - --dest /home/user/.config/retroarch/system - Details: /tmp/retrobios-x/install.log + Log: /tmp/retrobios-x/install.log @@ -472,7 +466,13 @@ - ^[[0;1;35mA/Enter^[[0m Exit + + + + + + + ^[[0;1;35mA/Enter^[[0m Exit ^[[0;2mY/o^[[0m Details === error ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: ^[[0;1;31mSomething went wrong^[[0m @@ -529,6 +529,7 @@ Up/Down, k/j Move A/Enter, Start Install Y, o, Tab Options + d Details B/Esc, Backspace Back q, Ctrl-C Quit ?, F1 This help @@ -546,7 +547,6 @@ - Any key closes this help === plan-games ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m @@ -554,11 +554,6 @@ ^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m For the 412 games on this card. - One region where the games prove it: nintendo-gba Europe. - 2 games get every BIOS of their system: Show the games. - ^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m - The ^[[0;33m1 wrong copy^[[0m is replaced, the old one kept in a backup folder. - Free space: 50.0 GB ^[[0;7;35m > Install^[[0m For the games on this card: yes 412 games @@ -566,12 +561,17 @@ Show the games Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit + + + + ^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Options ^[[0;2m?^[[0m Help === games ^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Games on this card^[[0m @@ -597,4 +597,54 @@ + ^[[0;1;35mA/Enter^[[0m Back +=== plan-details +^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m + + ^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m + The ^[[0;33m1 wrong copy^[[0m is replaced, the old one kept in a backup folder. + Free space: 50.0 GB + + + + + + + + + + + + + + + + + + + ^[[0;1;35mA/Enter^[[0m Back +=== result-details +^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m + + ^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404) + To put them back: python3 install.py \ + --restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 + Same choice without questions: + python3 install.py --platform retroarch \ + --dest /home/user/.config/retroarch/system + + + + + + + + + + + + + + + ^[[0;1;35mA/Enter^[[0m Back diff --git a/tests/fixtures/tui/confirm-120x40.txt b/tests/fixtures/tui/confirm-120x40.txt index c870132df..733790008 100644 --- a/tests/fixtures/tui/confirm-120x40.txt +++ b/tests/fixtures/tui/confirm-120x40.txt @@ -1,10 +1,8 @@ RetroBIOS: Confirm - Counted again for these choices. Nothing is written before Install. + Counted again for these choices. 1 file to download, 16.0 KB BIOS folder: ~/.config/retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back @@ -34,6 +32,8 @@ + + diff --git a/tests/fixtures/tui/confirm-40x12.txt b/tests/fixtures/tui/confirm-40x12.txt index 9e57bb545..22629b910 100644 --- a/tests/fixtures/tui/confirm-40x12.txt +++ b/tests/fixtures/tui/confirm-40x12.txt @@ -1,12 +1,12 @@ RetroBIOS: Confirm Counted again for these choices. - Nothing is written before Install. 1 file to download, 16.0 KB BIOS folder: ~/.co.../retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back + + + A Install B Back ? Help diff --git a/tests/fixtures/tui/confirm-40x15.txt b/tests/fixtures/tui/confirm-40x15.txt index d18f06885..572a2678f 100644 --- a/tests/fixtures/tui/confirm-40x15.txt +++ b/tests/fixtures/tui/confirm-40x15.txt @@ -1,15 +1,15 @@ RetroBIOS: Confirm Counted again for these choices. - Nothing is written before Install. 1 file to download, 16.0 KB BIOS folder: ~/.co.../retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back + + + A Install B Back ? Help diff --git a/tests/fixtures/tui/confirm-80x24.txt b/tests/fixtures/tui/confirm-80x24.txt index a44f71b14..ba06ca00a 100644 --- a/tests/fixtures/tui/confirm-80x24.txt +++ b/tests/fixtures/tui/confirm-80x24.txt @@ -1,10 +1,8 @@ RetroBIOS: Confirm - Counted again for these choices. Nothing is written before Install. + Counted again for these choices. 1 file to download, 16.0 KB BIOS folder: ~/.config/retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back @@ -21,4 +19,6 @@ + + A/Enter Install B/Esc Back ? Help diff --git a/tests/fixtures/tui/help-120x40.txt b/tests/fixtures/tui/help-120x40.txt index 71ba78093..edf48ff0f 100644 --- a/tests/fixtures/tui/help-120x40.txt +++ b/tests/fixtures/tui/help-120x40.txt @@ -3,6 +3,7 @@ Up/Down, k/j Move A/Enter, Start Install Y, o, Tab Options + d Details B/Esc, Backspace Back q, Ctrl-C Quit ?, F1 This help @@ -34,7 +35,6 @@ - Any key closes this help diff --git a/tests/fixtures/tui/help-40x12.txt b/tests/fixtures/tui/help-40x12.txt index 09b22304d..5362abd16 100644 --- a/tests/fixtures/tui/help-40x12.txt +++ b/tests/fixtures/tui/help-40x12.txt @@ -3,10 +3,10 @@ Up/Down, k/j Move A/Enter, Start Install Y, o, Tab Options + d Details B/Esc, Backspace Back q, Ctrl-C Quit ?, F1 This help - BIOS folder: - /home/user/.config/retroarch/system + Any key closes this help diff --git a/tests/fixtures/tui/help-40x15.txt b/tests/fixtures/tui/help-40x15.txt index 830acb87b..4ee7e371c 100644 --- a/tests/fixtures/tui/help-40x15.txt +++ b/tests/fixtures/tui/help-40x15.txt @@ -3,6 +3,7 @@ Up/Down, k/j Move A/Enter, Start Install Y, o, Tab Options + d Details B/Esc, Backspace Back q, Ctrl-C Quit ?, F1 This help @@ -11,5 +12,4 @@ /home/user/.config/retroarch/system - Any key closes this help diff --git a/tests/fixtures/tui/help-80x24.txt b/tests/fixtures/tui/help-80x24.txt index 557dd2178..b22ec4987 100644 --- a/tests/fixtures/tui/help-80x24.txt +++ b/tests/fixtures/tui/help-80x24.txt @@ -3,6 +3,7 @@ Up/Down, k/j Move A/Enter, Start Install Y, o, Tab Options + d Details B/Esc, Backspace Back q, Ctrl-C Quit ?, F1 This help @@ -20,5 +21,4 @@ - Any key closes this help diff --git a/tests/fixtures/tui/installing-120x40.txt b/tests/fixtures/tui/installing-120x40.txt index ff7651b12..3660aebba 100644 --- a/tests/fixtures/tui/installing-120x40.txt +++ b/tests/fixtures/tui/installing-120x40.txt @@ -7,7 +7,7 @@ B, Ctrl-C or Select+Start stops. What is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + diff --git a/tests/fixtures/tui/installing-40x12.txt b/tests/fixtures/tui/installing-40x12.txt index d56a30bbd..e92b7c2f3 100644 --- a/tests/fixtures/tui/installing-40x12.txt +++ b/tests/fixtures/tui/installing-40x12.txt @@ -8,5 +8,5 @@ is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + B Stop ? Help diff --git a/tests/fixtures/tui/installing-40x15.txt b/tests/fixtures/tui/installing-40x15.txt index 950ad6515..011e1dce2 100644 --- a/tests/fixtures/tui/installing-40x15.txt +++ b/tests/fixtures/tui/installing-40x15.txt @@ -8,7 +8,7 @@ is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + diff --git a/tests/fixtures/tui/installing-80x24.txt b/tests/fixtures/tui/installing-80x24.txt index fdd275588..338c47ec9 100644 --- a/tests/fixtures/tui/installing-80x24.txt +++ b/tests/fixtures/tui/installing-80x24.txt @@ -7,7 +7,7 @@ B, Ctrl-C or Select+Start stops. What is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + diff --git a/tests/fixtures/tui/plan-120x40.txt b/tests/fixtures/tui/plan-120x40.txt index 3ca54cb75..ca67ddd86 100644 --- a/tests/fixtures/tui/plan-120x40.txt +++ b/tests/fixtures/tui/plan-120x40.txt @@ -2,13 +2,11 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit @@ -34,6 +32,8 @@ + + diff --git a/tests/fixtures/tui/plan-40x12.txt b/tests/fixtures/tui/plan-40x12.txt index ef7c55353..26f08e468 100644 --- a/tests/fixtures/tui/plan-40x12.txt +++ b/tests/fixtures/tui/plan-40x12.txt @@ -3,10 +3,10 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 wrong copy: backed up, replaced. > Install Choose systems Copy from an old card or a folder + Details Options Quit A Install B Back Y Options ? Help diff --git a/tests/fixtures/tui/plan-40x15.txt b/tests/fixtures/tui/plan-40x15.txt index bf4817eda..5e2e6a6ea 100644 --- a/tests/fixtures/tui/plan-40x15.txt +++ b/tests/fixtures/tui/plan-40x15.txt @@ -3,13 +3,13 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 wrong copy: backed up, replaced. - 1 in place, 3 missing, 1 wrong copy - Free space: 50.0 GB > Install Choose systems Copy from an old card or a folder + Details Options Quit + + A Install B Back Y Options ? Help diff --git a/tests/fixtures/tui/plan-80x24.txt b/tests/fixtures/tui/plan-80x24.txt index 112f7c53a..09a860db6 100644 --- a/tests/fixtures/tui/plan-80x24.txt +++ b/tests/fixtures/tui/plan-80x24.txt @@ -2,13 +2,11 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit @@ -21,4 +19,6 @@ + + A/Enter Install B/Esc Back Y/o Options ? Help diff --git a/tests/fixtures/tui/plan-details-120x40.txt b/tests/fixtures/tui/plan-details-120x40.txt new file mode 100644 index 000000000..a875ed363 --- /dev/null +++ b/tests/fixtures/tui/plan-details-120x40.txt @@ -0,0 +1,40 @@ + RetroBIOS: Details + + 1 in place, 3 missing, 1 wrong copy + The 1 wrong copy is replaced, the old one kept in a backup folder. + Free space: 50.0 GB + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A/Enter Back diff --git a/tests/fixtures/tui/plan-details-40x12.txt b/tests/fixtures/tui/plan-details-40x12.txt new file mode 100644 index 000000000..01c228e8e --- /dev/null +++ b/tests/fixtures/tui/plan-details-40x12.txt @@ -0,0 +1,12 @@ + RetroBIOS: Details + + 1 in place, 3 missing, 1 wrong copy + The 1 wrong copy is replaced, the old + one kept in a backup folder. + Free space: 50.0 GB + + + + + + A Back diff --git a/tests/fixtures/tui/plan-details-40x15.txt b/tests/fixtures/tui/plan-details-40x15.txt new file mode 100644 index 000000000..04d3cb149 --- /dev/null +++ b/tests/fixtures/tui/plan-details-40x15.txt @@ -0,0 +1,15 @@ + RetroBIOS: Details + + 1 in place, 3 missing, 1 wrong copy + The 1 wrong copy is replaced, the old + one kept in a backup folder. + Free space: 50.0 GB + + + + + + + + + A Back diff --git a/tests/fixtures/tui/plan-details-80x24.txt b/tests/fixtures/tui/plan-details-80x24.txt new file mode 100644 index 000000000..5e33341d1 --- /dev/null +++ b/tests/fixtures/tui/plan-details-80x24.txt @@ -0,0 +1,24 @@ + RetroBIOS: Details + + 1 in place, 3 missing, 1 wrong copy + The 1 wrong copy is replaced, the old one kept in a backup folder. + Free space: 50.0 GB + + + + + + + + + + + + + + + + + + + A/Enter Back diff --git a/tests/fixtures/tui/plan-games-120x40.txt b/tests/fixtures/tui/plan-games-120x40.txt index 14b9e837a..157d4e6e9 100644 --- a/tests/fixtures/tui/plan-games-120x40.txt +++ b/tests/fixtures/tui/plan-games-120x40.txt @@ -3,11 +3,6 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system For the 412 games on this card. - One region where the games prove it: nintendo-gba Europe. - 2 games get every BIOS of their system: Show the games. - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install For the games on this card: yes 412 games @@ -15,6 +10,7 @@ Show the games Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit @@ -33,6 +29,10 @@ + + + + diff --git a/tests/fixtures/tui/plan-games-40x12.txt b/tests/fixtures/tui/plan-games-40x12.txt index 34dfd18a2..800da31b1 100644 --- a/tests/fixtures/tui/plan-games-40x12.txt +++ b/tests/fixtures/tui/plan-games-40x12.txt @@ -8,5 +8,5 @@ For the games on this card: yes 412 Only what starts: no Show the games - 1-4 of 8 + 1-4 of 9 A Install B Back Y Options ? Help diff --git a/tests/fixtures/tui/plan-games-40x15.txt b/tests/fixtures/tui/plan-games-40x15.txt index b8573927e..2d208f0e1 100644 --- a/tests/fixtures/tui/plan-games-40x15.txt +++ b/tests/fixtures/tui/plan-games-40x15.txt @@ -3,13 +3,13 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - For the 412 games on this card. > Install For the games on this card: yes 412 Only what starts: no Show the games Choose systems Copy from an old card or a folder + Details Options Quit A Install B Back Y Options ? Help diff --git a/tests/fixtures/tui/plan-games-80x24.txt b/tests/fixtures/tui/plan-games-80x24.txt index a6389d14b..81c89f428 100644 --- a/tests/fixtures/tui/plan-games-80x24.txt +++ b/tests/fixtures/tui/plan-games-80x24.txt @@ -3,11 +3,6 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system For the 412 games on this card. - One region where the games prove it: nintendo-gba Europe. - 2 games get every BIOS of their system: Show the games. - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install For the games on this card: yes 412 games @@ -15,10 +10,15 @@ Show the games Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit + + + + A/Enter Install B/Esc Back Y/o Options ? Help diff --git a/tests/fixtures/tui/plan-in-place-120x40.txt b/tests/fixtures/tui/plan-in-place-120x40.txt index 0e5b41f91..7001d8a90 100644 --- a/tests/fixtures/tui/plan-in-place-120x40.txt +++ b/tests/fixtures/tui/plan-in-place-120x40.txt @@ -2,11 +2,9 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Close + Details Options @@ -34,6 +32,8 @@ + + diff --git a/tests/fixtures/tui/plan-in-place-40x12.txt b/tests/fixtures/tui/plan-in-place-40x12.txt index 83ce5207e..7b46aabc7 100644 --- a/tests/fixtures/tui/plan-in-place-40x12.txt +++ b/tests/fixtures/tui/plan-in-place-40x12.txt @@ -3,10 +3,10 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB + > Close + Details Options + + A Close B Back Y Options ? Help diff --git a/tests/fixtures/tui/plan-in-place-40x15.txt b/tests/fixtures/tui/plan-in-place-40x15.txt index f5f2d9033..182af92d6 100644 --- a/tests/fixtures/tui/plan-in-place-40x15.txt +++ b/tests/fixtures/tui/plan-in-place-40x15.txt @@ -3,13 +3,13 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB > Close + Details Options + + + A Close B Back Y Options ? Help diff --git a/tests/fixtures/tui/plan-in-place-80x24.txt b/tests/fixtures/tui/plan-in-place-80x24.txt index da0702005..36673c825 100644 --- a/tests/fixtures/tui/plan-in-place-80x24.txt +++ b/tests/fixtures/tui/plan-in-place-80x24.txt @@ -2,11 +2,9 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Close + Details Options @@ -21,4 +19,6 @@ + + A/Enter Close B/Esc Back Y/o Options ? Help diff --git a/tests/fixtures/tui/result-120x40.txt b/tests/fixtures/tui/result-120x40.txt index 550ec7724..628078bd4 100644 --- a/tests/fixtures/tui/result-120x40.txt +++ b/tests/fixtures/tui/result-120x40.txt @@ -2,14 +2,9 @@ 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 - To put them back: python3 install.py \ - --restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 - Same choice without questions: - python3 install.py --platform retroarch --dest /home/user/.config/retroarch/system - Details: /tmp/retrobios-x/install.log + Log: /tmp/retrobios-x/install.log @@ -37,4 +32,9 @@ - A/Enter Exit + + + + + + A/Enter Exit Y/o Details diff --git a/tests/fixtures/tui/result-40x12.txt b/tests/fixtures/tui/result-40x12.txt index 12339e200..d0c87bb72 100644 --- a/tests/fixtures/tui/result-40x12.txt +++ b/tests/fixtures/tui/result-40x12.txt @@ -3,10 +3,10 @@ 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/ retrobios-backup/2026-10-23_1200 - 1-8 of 17 - A Exit ^v Scroll + Log: /tmp/retrobios-x/install.log + + A Exit Y Details diff --git a/tests/fixtures/tui/result-40x15.txt b/tests/fixtures/tui/result-40x15.txt index 61db5344b..395f4cf8e 100644 --- a/tests/fixtures/tui/result-40x15.txt +++ b/tests/fixtures/tui/result-40x15.txt @@ -3,13 +3,13 @@ 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/ retrobios-backup/2026-10-23_1200 - To put them back: python3 install.py \ - --restore .../2026-10-23_1200 - Shortened to fit this window. - 1-11 of 17 - A Exit ^v Scroll + Log: /tmp/retrobios-x/install.log + + + + + A Exit Y Details diff --git a/tests/fixtures/tui/result-80x24.txt b/tests/fixtures/tui/result-80x24.txt index ab4770376..ca5097819 100644 --- a/tests/fixtures/tui/result-80x24.txt +++ b/tests/fixtures/tui/result-80x24.txt @@ -2,16 +2,10 @@ 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 - To put them back: python3 install.py \ - --restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 - Same choice without questions: - python3 install.py --platform retroarch \ - --dest /home/user/.config/retroarch/system - Details: /tmp/retrobios-x/install.log + Log: /tmp/retrobios-x/install.log @@ -21,4 +15,10 @@ - A/Enter Exit + + + + + + + A/Enter Exit Y/o Details diff --git a/tests/fixtures/tui/result-details-120x40.txt b/tests/fixtures/tui/result-details-120x40.txt new file mode 100644 index 000000000..1896a865d --- /dev/null +++ b/tests/fixtures/tui/result-details-120x40.txt @@ -0,0 +1,40 @@ + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + To put them back: python3 install.py \ + --restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 + Same choice without questions: + python3 install.py --platform retroarch --dest /home/user/.config/retroarch/system + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A/Enter Back diff --git a/tests/fixtures/tui/result-details-40x12.txt b/tests/fixtures/tui/result-details-40x12.txt new file mode 100644 index 000000000..063668de9 --- /dev/null +++ b/tests/fixtures/tui/result-details-40x12.txt @@ -0,0 +1,12 @@ + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + To put them back: python3 install.py \ + --restore .../2026-10-23_1200 + Shortened to fit this window. + Same choice without questions: + python3 install.py \ + --platform retroarch \ + --dest .../retroarch/system + Shortened to fit this window. + A Back diff --git a/tests/fixtures/tui/result-details-40x15.txt b/tests/fixtures/tui/result-details-40x15.txt new file mode 100644 index 000000000..efd9f6523 --- /dev/null +++ b/tests/fixtures/tui/result-details-40x15.txt @@ -0,0 +1,15 @@ + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + To put them back: python3 install.py \ + --restore .../2026-10-23_1200 + Shortened to fit this window. + Same choice without questions: + python3 install.py \ + --platform retroarch \ + --dest .../retroarch/system + Shortened to fit this window. + + + + A Back diff --git a/tests/fixtures/tui/result-details-80x24.txt b/tests/fixtures/tui/result-details-80x24.txt new file mode 100644 index 000000000..9d05dd8aa --- /dev/null +++ b/tests/fixtures/tui/result-details-80x24.txt @@ -0,0 +1,24 @@ + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + To put them back: python3 install.py \ + --restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 + Same choice without questions: + python3 install.py --platform retroarch \ + --dest /home/user/.config/retroarch/system + + + + + + + + + + + + + + + + A/Enter Back diff --git a/tests/fixtures/tui/route-evmapy.txt b/tests/fixtures/tui/route-evmapy.txt index 5f3beed24..b8a915afb 100644 --- a/tests/fixtures/tui/route-evmapy.txt +++ b/tests/fixtures/tui/route-evmapy.txt @@ -407,10 +407,10 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 wrong copy: backed up, replaced. > Install Choose systems Copy from an old card or a folder + Details Options Quit A Install B Back Y Options @@ -420,28 +420,26 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 wrong copy: backed up, replaced. - 1 in place, 3 missing, 1 wrong copy - Free space: 50.0 GB > Install Choose systems Copy from an old card or a folder + Details Options Quit + + A Install B Back Y Options === plan 80x24 RetroBIOS: RetroArch 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit @@ -454,6 +452,8 @@ + + A Install B Back Y Options === plan-in-place 40x12 RetroBIOS: RetroArch @@ -461,12 +461,12 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB + > Close + Details Options + + A Close B Back Y Options === plan-in-place 40x15 RetroBIOS: RetroArch @@ -474,26 +474,24 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB > Close + Details Options + + + A Close B Back Y Options === plan-in-place 80x24 RetroBIOS: RetroArch Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Close + Details Options @@ -508,6 +506,8 @@ + + A Close B Back Y Options === systems 40x12 RetroBIOS: Choose systems @@ -779,39 +779,37 @@ RetroBIOS: Confirm Counted again for these choices. - Nothing is written before Install. 1 file to download, 16.0 KB BIOS folder: ~/.co.../retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back + + + A Install B Back === confirm 40x15 RetroBIOS: Confirm Counted again for these choices. - Nothing is written before Install. 1 file to download, 16.0 KB BIOS folder: ~/.co.../retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back + + + A Install B Back === confirm 80x24 RetroBIOS: Confirm - Counted again for these choices. Nothing is written before Install. + Counted again for these choices. 1 file to download, 16.0 KB BIOS folder: ~/.config/retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back @@ -828,6 +826,8 @@ + + A Install B Back === installing 40x12 RetroBIOS: Installing @@ -839,7 +839,7 @@ B stops. What is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + B Stop === installing 40x15 @@ -852,7 +852,7 @@ B stops. What is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + @@ -868,7 +868,7 @@ B stops. What is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + @@ -883,45 +883,15 @@ B Stop -=== result 40x12 - RetroBIOS: Finished with errors - - 3 installed, 1 failed. - BIOS folder: - /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) - Run it again to retry only those. - The files it replaced are kept in - /home/user/.config/retroarch/ - retrobios-backup/2026-10-23_1200 - Details: /tmp/retrobios-x/install.log - A Exit -=== result 40x15 - RetroBIOS: Finished with errors - - 3 installed, 1 failed. - BIOS folder: - /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) - Run it again to retry only those. - The files it replaced are kept in - /home/user/.config/retroarch/ - retrobios-backup/2026-10-23_1200 - Details: /tmp/retrobios-x/install.log - - - - A Exit === result 80x24 RetroBIOS: Finished with errors 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 - Details: /tmp/retrobios-x/install.log + Log: /tmp/retrobios-x/install.log @@ -936,7 +906,8 @@ - A Exit + + A Exit Y Details === error 40x12 RetroBIOS: Something went wrong @@ -1006,12 +977,12 @@ D-pad, Up/Down Move A, Start, Enter Install Y, Tab, o Options + d Details B, Select, Esc Back q, Ctrl-C Quit BIOS folder: /home/user/.config/retroarch/system - Any key closes this help === help 40x15 RetroBIOS: Keys @@ -1019,6 +990,7 @@ D-pad, Up/Down Move A, Start, Enter Install Y, Tab, o Options + d Details B, Select, Esc Back q, Ctrl-C Quit @@ -1027,7 +999,6 @@ - Any key closes this help === help 80x24 RetroBIOS: Keys @@ -1035,6 +1006,7 @@ D-pad, Up/Down Move A, Start, Enter Install Y, Tab, o Options + d Details B, Select, Esc Back q, Ctrl-C Quit @@ -1052,7 +1024,6 @@ - Any key closes this help === plan-games 40x12 RetroBIOS: RetroArch @@ -1065,7 +1036,7 @@ For the games on this card: yes 412 Only what starts: no Show the games - 1-4 of 8 + 1-4 of 9 A Install B Back Y Options === plan-games 40x15 RetroBIOS: RetroArch @@ -1073,13 +1044,13 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - For the 412 games on this card. > Install For the games on this card: yes 412 Only what starts: no Show the games Choose systems Copy from an old card or a folder + Details Options Quit A Install B Back Y Options @@ -1089,11 +1060,6 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system For the 412 games on this card. - One region where the games prove it: nintendo-gba Europe. - 2 games get every BIOS of their system: Show the games. - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install For the games on this card: yes 412 games @@ -1101,12 +1067,17 @@ Show the games Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit + + + + A Install B Back Y Options === games 80x24 RetroBIOS: Games on this card @@ -1132,4 +1103,83 @@ + A Back +=== plan-details 80x24 + RetroBIOS: Details + + 1 in place, 3 missing, 1 wrong copy + The 1 wrong copy is replaced, the old one kept in a backup folder. + Free space: 50.0 GB + + + + + + + + + + + + + + + + + + + A Back +=== result-details 40x12 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + + + + + + + + + A Back +=== result-details 40x15 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + + + + + + + + + + + + A Back +=== result-details 80x24 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + + + + + + + + + + + + + + + + + + + + A Back diff --git a/tests/fixtures/tui/route-gptokeyb.txt b/tests/fixtures/tui/route-gptokeyb.txt index 13e24690f..f1179b688 100644 --- a/tests/fixtures/tui/route-gptokeyb.txt +++ b/tests/fixtures/tui/route-gptokeyb.txt @@ -407,10 +407,10 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 wrong copy: backed up, replaced. > Install Choose systems Copy from an old card or a folder + Details Options Quit A Install B Back Y Options @@ -420,28 +420,26 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 wrong copy: backed up, replaced. - 1 in place, 3 missing, 1 wrong copy - Free space: 50.0 GB > Install Choose systems Copy from an old card or a folder + Details Options Quit + + A Install B Back Y Options === plan 80x24 RetroBIOS: RetroArch 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit @@ -454,6 +452,8 @@ + + A Install B Back Y Options === plan-in-place 40x12 RetroBIOS: RetroArch @@ -461,12 +461,12 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB + > Close + Details Options + + A Close B Back Y Options === plan-in-place 40x15 RetroBIOS: RetroArch @@ -474,26 +474,24 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB > Close + Details Options + + + A Close B Back Y Options === plan-in-place 80x24 RetroBIOS: RetroArch Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Close + Details Options @@ -508,6 +506,8 @@ + + A Close B Back Y Options === systems 40x12 RetroBIOS: Choose systems @@ -779,39 +779,37 @@ RetroBIOS: Confirm Counted again for these choices. - Nothing is written before Install. 1 file to download, 16.0 KB BIOS folder: ~/.co.../retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back + + + A Install B Back === confirm 40x15 RetroBIOS: Confirm Counted again for these choices. - Nothing is written before Install. 1 file to download, 16.0 KB BIOS folder: ~/.co.../retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back + + + A Install B Back === confirm 80x24 RetroBIOS: Confirm - Counted again for these choices. Nothing is written before Install. + Counted again for these choices. 1 file to download, 16.0 KB BIOS folder: ~/.config/retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back @@ -828,6 +826,8 @@ + + A Install B Back === installing 40x12 RetroBIOS: Installing @@ -840,7 +840,7 @@ stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + B Stop === installing 40x15 RetroBIOS: Installing @@ -853,7 +853,7 @@ stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + @@ -868,7 +868,7 @@ B or Select+Start stops. What is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + @@ -883,45 +883,15 @@ B Stop -=== result 40x12 - RetroBIOS: Finished with errors - - 3 installed, 1 failed. - BIOS folder: - /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) - Run it again to retry only those. - The files it replaced are kept in - /home/user/.config/retroarch/ - retrobios-backup/2026-10-23_1200 - Details: /tmp/retrobios-x/install.log - A Exit -=== result 40x15 - RetroBIOS: Finished with errors - - 3 installed, 1 failed. - BIOS folder: - /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) - Run it again to retry only those. - The files it replaced are kept in - /home/user/.config/retroarch/ - retrobios-backup/2026-10-23_1200 - Details: /tmp/retrobios-x/install.log - - - - A Exit === result 80x24 RetroBIOS: Finished with errors 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 - Details: /tmp/retrobios-x/install.log + Log: /tmp/retrobios-x/install.log @@ -936,7 +906,8 @@ - A Exit + + A Exit Y Details === error 40x12 RetroBIOS: Something went wrong @@ -1006,12 +977,12 @@ D-pad, Up/Down Move A, Start, Enter Install Y, Tab, o Options + d Details B, Select, Esc Back q, Ctrl-C Quit Select, then Start Quit at once - BIOS folder: - /home/user/.config/retroarch/system + Any key closes this help === help 40x15 RetroBIOS: Keys @@ -1019,6 +990,7 @@ D-pad, Up/Down Move A, Start, Enter Install Y, Tab, o Options + d Details B, Select, Esc Back q, Ctrl-C Quit Select, then Start Quit at once @@ -1027,7 +999,6 @@ /home/user/.config/retroarch/system - Any key closes this help === help 80x24 RetroBIOS: Keys @@ -1035,6 +1006,7 @@ D-pad, Up/Down Move A, Start, Enter Install Y, Tab, o Options + d Details B, Select, Esc Back q, Ctrl-C Quit Select, then Start Quit at once @@ -1052,7 +1024,6 @@ - Any key closes this help === plan-games 40x12 RetroBIOS: RetroArch @@ -1065,7 +1036,7 @@ For the games on this card: yes 412 Only what starts: no Show the games - 1-4 of 8 + 1-4 of 9 A Install B Back Y Options === plan-games 40x15 RetroBIOS: RetroArch @@ -1073,13 +1044,13 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - For the 412 games on this card. > Install For the games on this card: yes 412 Only what starts: no Show the games Choose systems Copy from an old card or a folder + Details Options Quit A Install B Back Y Options @@ -1089,11 +1060,6 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system For the 412 games on this card. - One region where the games prove it: nintendo-gba Europe. - 2 games get every BIOS of their system: Show the games. - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install For the games on this card: yes 412 games @@ -1101,12 +1067,17 @@ Show the games Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit + + + + A Install B Back Y Options === games 80x24 RetroBIOS: Games on this card @@ -1132,4 +1103,83 @@ + A Back +=== plan-details 80x24 + RetroBIOS: Details + + 1 in place, 3 missing, 1 wrong copy + The 1 wrong copy is replaced, the old one kept in a backup folder. + Free space: 50.0 GB + + + + + + + + + + + + + + + + + + + A Back +=== result-details 40x12 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + + + + + + + + + A Back +=== result-details 40x15 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + + + + + + + + + + + + A Back +=== result-details 80x24 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + + + + + + + + + + + + + + + + + + + + A Back diff --git a/tests/fixtures/tui/route-gptokeyb_muxterm.txt b/tests/fixtures/tui/route-gptokeyb_muxterm.txt index 9342b9667..c285fd3d9 100644 --- a/tests/fixtures/tui/route-gptokeyb_muxterm.txt +++ b/tests/fixtures/tui/route-gptokeyb_muxterm.txt @@ -407,10 +407,10 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 wrong copy: backed up, replaced. > Install Choose systems Copy from an old card or a folder + Details Options Quit A Install B Back Y Options @@ -420,28 +420,26 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 wrong copy: backed up, replaced. - 1 in place, 3 missing, 1 wrong copy - Free space: 50.0 GB > Install Choose systems Copy from an old card or a folder + Details Options Quit + + A Install B Back Y Options === plan 80x24 RetroBIOS: RetroArch 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit @@ -454,6 +452,8 @@ + + A Install B Back Y Options === plan-in-place 40x12 RetroBIOS: RetroArch @@ -461,12 +461,12 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB + > Close + Details Options + + A Close B Back Y Options === plan-in-place 40x15 RetroBIOS: RetroArch @@ -474,26 +474,24 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB > Close + Details Options + + + A Close B Back Y Options === plan-in-place 80x24 RetroBIOS: RetroArch Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Close + Details Options @@ -508,6 +506,8 @@ + + A Close B Back Y Options === systems 40x12 RetroBIOS: Choose systems @@ -779,39 +779,37 @@ RetroBIOS: Confirm Counted again for these choices. - Nothing is written before Install. 1 file to download, 16.0 KB BIOS folder: ~/.co.../retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back + + + A Install B Back === confirm 40x15 RetroBIOS: Confirm Counted again for these choices. - Nothing is written before Install. 1 file to download, 16.0 KB BIOS folder: ~/.co.../retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back + + + A Install B Back === confirm 80x24 RetroBIOS: Confirm - Counted again for these choices. Nothing is written before Install. + Counted again for these choices. 1 file to download, 16.0 KB BIOS folder: ~/.config/retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back @@ -828,6 +826,8 @@ + + A Install B Back === installing 40x12 RetroBIOS: Installing @@ -840,7 +840,7 @@ stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + B Stop === installing 40x15 RetroBIOS: Installing @@ -853,7 +853,7 @@ stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + @@ -868,7 +868,7 @@ B or Select+Start stops. What is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + @@ -883,45 +883,15 @@ B Stop -=== result 40x12 - RetroBIOS: Finished with errors - - 3 installed, 1 failed. - BIOS folder: - /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) - Run it again to retry only those. - The files it replaced are kept in - /home/user/.config/retroarch/ - retrobios-backup/2026-10-23_1200 - Details: /tmp/retrobios-x/install.log - A Exit -=== result 40x15 - RetroBIOS: Finished with errors - - 3 installed, 1 failed. - BIOS folder: - /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) - Run it again to retry only those. - The files it replaced are kept in - /home/user/.config/retroarch/ - retrobios-backup/2026-10-23_1200 - Details: /tmp/retrobios-x/install.log - - - - A Exit === result 80x24 RetroBIOS: Finished with errors 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 - Details: /tmp/retrobios-x/install.log + Log: /tmp/retrobios-x/install.log @@ -936,7 +906,8 @@ - A Exit + + A Exit Y Details === error 40x12 RetroBIOS: Something went wrong @@ -1006,12 +977,12 @@ D-pad, Up/Down Move A, Start, Enter Install Y, Tab, o Options + d Details B, Select, Esc Back q, Ctrl-C Quit Select, then Start Quit at once - BIOS folder: - /home/user/.config/retroarch/system + Any key closes this help === help 40x15 RetroBIOS: Keys @@ -1019,6 +990,7 @@ D-pad, Up/Down Move A, Start, Enter Install Y, Tab, o Options + d Details B, Select, Esc Back q, Ctrl-C Quit Select, then Start Quit at once @@ -1027,7 +999,6 @@ /home/user/.config/retroarch/system - Any key closes this help === help 80x24 RetroBIOS: Keys @@ -1035,6 +1006,7 @@ D-pad, Up/Down Move A, Start, Enter Install Y, Tab, o Options + d Details B, Select, Esc Back q, Ctrl-C Quit Select, then Start Quit at once @@ -1052,7 +1024,6 @@ - Any key closes this help === plan-games 40x12 RetroBIOS: RetroArch @@ -1065,7 +1036,7 @@ For the games on this card: yes 412 Only what starts: no Show the games - 1-4 of 8 + 1-4 of 9 A Install B Back Y Options === plan-games 40x15 RetroBIOS: RetroArch @@ -1073,13 +1044,13 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - For the 412 games on this card. > Install For the games on this card: yes 412 Only what starts: no Show the games Choose systems Copy from an old card or a folder + Details Options Quit A Install B Back Y Options @@ -1089,11 +1060,6 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system For the 412 games on this card. - One region where the games prove it: nintendo-gba Europe. - 2 games get every BIOS of their system: Show the games. - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install For the games on this card: yes 412 games @@ -1101,12 +1067,17 @@ Show the games Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit + + + + A Install B Back Y Options === games 80x24 RetroBIOS: Games on this card @@ -1132,4 +1103,83 @@ + A Back +=== plan-details 80x24 + RetroBIOS: Details + + 1 in place, 3 missing, 1 wrong copy + The 1 wrong copy is replaced, the old one kept in a backup folder. + Free space: 50.0 GB + + + + + + + + + + + + + + + + + + + A Back +=== result-details 40x12 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + + + + + + + + + A Back +=== result-details 40x15 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + + + + + + + + + + + + A Back +=== result-details 80x24 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + + + + + + + + + + + + + + + + + + + + A Back diff --git a/tests/fixtures/tui/route-keys.txt b/tests/fixtures/tui/route-keys.txt index 4d2e586eb..557245079 100644 --- a/tests/fixtures/tui/route-keys.txt +++ b/tests/fixtures/tui/route-keys.txt @@ -382,10 +382,10 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 wrong copy: backed up, replaced. > Install Choose systems Copy from an old card or a folder + Details Options Quit Enter Install Esc Back o Options @@ -395,28 +395,26 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 wrong copy: backed up, replaced. - 1 in place, 3 missing, 1 wrong copy - Free space: 50.0 GB > Install Choose systems Copy from an old card or a folder + Details Options Quit + + Enter Install Esc Back o Options === plan 80x24 RetroBIOS: RetroArch 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit @@ -429,6 +427,8 @@ + + Enter Install Esc Back o Options ? Help === plan-in-place 40x12 RetroBIOS: RetroArch @@ -436,12 +436,12 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB + > Close + Details Options + + Enter Close Esc Back o Options === plan-in-place 40x15 RetroBIOS: RetroArch @@ -449,26 +449,24 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB > Close + Details Options + + + Enter Close Esc Back o Options === plan-in-place 80x24 RetroBIOS: RetroArch Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Close + Details Options @@ -483,6 +481,8 @@ + + Enter Close Esc Back o Options ? Help === systems 40x12 RetroBIOS: Choose systems @@ -812,39 +812,37 @@ RetroBIOS: Confirm Counted again for these choices. - Nothing is written before Install. 1 file to download, 16.0 KB BIOS folder: ~/.co.../retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back + + + Enter Install Esc Back ? Help === confirm 40x15 RetroBIOS: Confirm Counted again for these choices. - Nothing is written before Install. 1 file to download, 16.0 KB BIOS folder: ~/.co.../retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back + + + Enter Install Esc Back ? Help === confirm 80x24 RetroBIOS: Confirm - Counted again for these choices. Nothing is written before Install. + Counted again for these choices. 1 file to download, 16.0 KB BIOS folder: ~/.config/retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back @@ -861,6 +859,8 @@ + + Enter Install Esc Back ? Help === installing 40x12 RetroBIOS: Installing @@ -873,7 +873,7 @@ stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + Esc Stop ? Help === installing 40x15 RetroBIOS: Installing @@ -886,7 +886,7 @@ stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + @@ -901,7 +901,7 @@ Esc or Ctrl-C stops. What is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + @@ -922,44 +922,38 @@ 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/ retrobios-backup/2026-10-23_1200 - 1-8 of 17 - Enter Exit ^v Scroll + Log: /tmp/retrobios-x/install.log + + Enter Exit o Details === result 40x15 RetroBIOS: Finished with errors 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/ retrobios-backup/2026-10-23_1200 - To put them back: python3 install.py \ - --restore .../2026-10-23_1200 - Shortened to fit this window. - 1-11 of 17 - Enter Exit ^v Scroll + Log: /tmp/retrobios-x/install.log + + + + + Enter Exit o Details === result 80x24 RetroBIOS: Finished with errors 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 - To put them back: python3 install.py \ - --restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 - Same choice without questions: - python3 install.py --platform retroarch \ - --dest /home/user/.config/retroarch/system - Details: /tmp/retrobios-x/install.log + Log: /tmp/retrobios-x/install.log @@ -969,7 +963,13 @@ - Enter Exit + + + + + + + Enter Exit o Details === error 40x12 RetroBIOS: Something went wrong @@ -1084,12 +1084,12 @@ Up/Down, k/j Move Enter Install o, Tab Options + d Details Esc, Backspace Back q, Ctrl-C Quit ?, F1 This help - BIOS folder: - /home/user/.config/retroarch/system + Any key closes this help === help 40x15 RetroBIOS: Keys @@ -1097,6 +1097,7 @@ Up/Down, k/j Move Enter Install o, Tab Options + d Details Esc, Backspace Back q, Ctrl-C Quit ?, F1 This help @@ -1105,7 +1106,6 @@ /home/user/.config/retroarch/system - Any key closes this help === help 80x24 RetroBIOS: Keys @@ -1113,6 +1113,7 @@ Up/Down, k/j Move Enter Install o, Tab Options + d Details Esc, Backspace Back q, Ctrl-C Quit ?, F1 This help @@ -1130,7 +1131,6 @@ - Any key closes this help === plan-games 40x12 RetroBIOS: RetroArch @@ -1143,7 +1143,7 @@ For the games on this card: yes 412 Only what starts: no Show the games - 1-4 of 8 + 1-4 of 9 Enter Install Esc Back o Options === plan-games 40x15 RetroBIOS: RetroArch @@ -1151,13 +1151,13 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - For the 412 games on this card. > Install For the games on this card: yes 412 Only what starts: no Show the games Choose systems Copy from an old card or a folder + Details Options Quit Enter Install Esc Back o Options @@ -1167,11 +1167,6 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system For the 412 games on this card. - One region where the games prove it: nintendo-gba Europe. - 2 games get every BIOS of their system: Show the games. - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install For the games on this card: yes 412 games @@ -1179,12 +1174,17 @@ Show the games Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit + + + + Enter Install Esc Back o Options ? Help === games 40x12 RetroBIOS: Games on this card @@ -1239,4 +1239,112 @@ + Enter Back +=== plan-details 40x12 + RetroBIOS: Details + + 1 in place, 3 missing, 1 wrong copy + The 1 wrong copy is replaced, the old + one kept in a backup folder. + Free space: 50.0 GB + + + + + + Enter Back +=== plan-details 40x15 + RetroBIOS: Details + + 1 in place, 3 missing, 1 wrong copy + The 1 wrong copy is replaced, the old + one kept in a backup folder. + Free space: 50.0 GB + + + + + + + + + Enter Back +=== plan-details 80x24 + RetroBIOS: Details + + 1 in place, 3 missing, 1 wrong copy + The 1 wrong copy is replaced, the old one kept in a backup folder. + Free space: 50.0 GB + + + + + + + + + + + + + + + + + + + Enter Back +=== result-details 40x12 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + To put them back: python3 install.py \ + --restore .../2026-10-23_1200 + Shortened to fit this window. + Same choice without questions: + python3 install.py \ + --platform retroarch \ + --dest .../retroarch/system + Shortened to fit this window. + Enter Back +=== result-details 40x15 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + To put them back: python3 install.py \ + --restore .../2026-10-23_1200 + Shortened to fit this window. + Same choice without questions: + python3 install.py \ + --platform retroarch \ + --dest .../retroarch/system + Shortened to fit this window. + + + + Enter Back +=== result-details 80x24 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + To put them back: python3 install.py \ + --restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 + Same choice without questions: + python3 install.py --platform retroarch \ + --dest /home/user/.config/retroarch/system + + + + + + + + + + + + + + + Enter Back diff --git a/tests/fixtures/tui/route-miyoo.txt b/tests/fixtures/tui/route-miyoo.txt index ab456df22..9c0dc475a 100644 --- a/tests/fixtures/tui/route-miyoo.txt +++ b/tests/fixtures/tui/route-miyoo.txt @@ -436,10 +436,10 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 wrong copy: backed up, replaced. > Install Choose systems Copy from an old card or a folder + Details Options Quit A Install R2 Back L2 Options @@ -449,28 +449,26 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 wrong copy: backed up, replaced. - 1 in place, 3 missing, 1 wrong copy - Free space: 50.0 GB > Install Choose systems Copy from an old card or a folder + Details Options Quit + + A Install R2 Back L2 Options === plan 80x24 RetroBIOS: RetroArch 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit @@ -483,6 +481,8 @@ + + A Install R2 Back L2 Options === plan-in-place 40x12 RetroBIOS: RetroArch @@ -490,12 +490,12 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB + > Close + Details Options + + A Close R2 Back L2 Options === plan-in-place 40x15 RetroBIOS: RetroArch @@ -503,26 +503,24 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB > Close + Details Options + + + A Close R2 Back L2 Options === plan-in-place 80x24 RetroBIOS: RetroArch Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Close + Details Options @@ -537,6 +535,8 @@ + + A Close R2 Back L2 Options === systems 40x12 RetroBIOS: Choose systems @@ -808,39 +808,37 @@ RetroBIOS: Confirm Counted again for these choices. - Nothing is written before Install. 1 file to download, 16.0 KB BIOS folder: ~/.co.../retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back + + + A Install R2 Back === confirm 40x15 RetroBIOS: Confirm Counted again for these choices. - Nothing is written before Install. 1 file to download, 16.0 KB BIOS folder: ~/.co.../retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back + + + A Install R2 Back === confirm 80x24 RetroBIOS: Confirm - Counted again for these choices. Nothing is written before Install. + Counted again for these choices. 1 file to download, 16.0 KB BIOS folder: ~/.config/retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back @@ -857,6 +855,8 @@ + + A Install R2 Back === installing 40x12 RetroBIOS: Installing @@ -868,7 +868,7 @@ R2 stops. What is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + R2 Stop === installing 40x15 @@ -881,7 +881,7 @@ R2 stops. What is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + @@ -897,7 +897,7 @@ R2 stops. What is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + @@ -918,39 +918,38 @@ 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/ retrobios-backup/2026-10-23_1200 - Details: /tmp/retrobios-x/install.log - A Exit + Log: /tmp/retrobios-x/install.log + + A Exit L2 Details === result 40x15 RetroBIOS: Finished with errors 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/ retrobios-backup/2026-10-23_1200 - Details: /tmp/retrobios-x/install.log + Log: /tmp/retrobios-x/install.log - A Exit + + A Exit L2 Details === result 80x24 RetroBIOS: Finished with errors 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 - Details: /tmp/retrobios-x/install.log + Log: /tmp/retrobios-x/install.log @@ -965,7 +964,8 @@ - A Exit + + A Exit L2 Details === error 40x12 RetroBIOS: Something went wrong @@ -1080,12 +1080,12 @@ D-pad, Up/Down Move A, Start, Enter Install L2, Tab, o Options + d Details R2, Esc, Backspace Back q, Ctrl-C Quit B Sends no key here - BIOS folder: - /home/user/.config/retroarch/system + Any key closes this help === help 40x15 RetroBIOS: Keys @@ -1093,6 +1093,7 @@ D-pad, Up/Down Move A, Start, Enter Install L2, Tab, o Options + d Details R2, Esc, Backspace Back q, Ctrl-C Quit B Sends no key here @@ -1101,7 +1102,6 @@ /home/user/.config/retroarch/system - Any key closes this help === help 80x24 RetroBIOS: Keys @@ -1109,6 +1109,7 @@ D-pad, Up/Down Move A, Start, Enter Install L2, Tab, o Options + d Details R2, Esc, Backspace Back q, Ctrl-C Quit B Sends no key here @@ -1126,7 +1127,6 @@ - Any key closes this help === plan-games 40x12 RetroBIOS: RetroArch @@ -1139,7 +1139,7 @@ For the games on this card: yes 412 Only what starts: no Show the games - 1-4 of 8 + 1-4 of 9 A Install R2 Back L2 Options === plan-games 40x15 RetroBIOS: RetroArch @@ -1147,13 +1147,13 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - For the 412 games on this card. > Install For the games on this card: yes 412 Only what starts: no Show the games Choose systems Copy from an old card or a folder + Details Options Quit A Install R2 Back L2 Options @@ -1163,11 +1163,6 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system For the 412 games on this card. - One region where the games prove it: nintendo-gba Europe. - 2 games get every BIOS of their system: Show the games. - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install For the games on this card: yes 412 games @@ -1175,12 +1170,17 @@ Show the games Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit + + + + A Install R2 Back L2 Options === games 80x24 RetroBIOS: Games on this card @@ -1206,4 +1206,83 @@ + A Back +=== plan-details 80x24 + RetroBIOS: Details + + 1 in place, 3 missing, 1 wrong copy + The 1 wrong copy is replaced, the old one kept in a backup folder. + Free space: 50.0 GB + + + + + + + + + + + + + + + + + + + A Back +=== result-details 40x12 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + + + + + + + + + A Back +=== result-details 40x15 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + + + + + + + + + + + + A Back +=== result-details 80x24 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + + + + + + + + + + + + + + + + + + + + A Back diff --git a/tests/fixtures/tui/route-muxterm.txt b/tests/fixtures/tui/route-muxterm.txt index 2f19f13e7..f118e37e6 100644 --- a/tests/fixtures/tui/route-muxterm.txt +++ b/tests/fixtures/tui/route-muxterm.txt @@ -436,10 +436,10 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 wrong copy: backed up, replaced. > Install Choose systems Copy from an old card or a folder + Details Options Quit Start Install B Back @@ -449,28 +449,26 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 wrong copy: backed up, replaced. - 1 in place, 3 missing, 1 wrong copy - Free space: 50.0 GB > Install Choose systems Copy from an old card or a folder + Details Options Quit + + Start Install B Back === plan 80x24 RetroBIOS: RetroArch 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit @@ -483,6 +481,8 @@ + + Start Install B Back === plan-in-place 40x12 RetroBIOS: RetroArch @@ -490,12 +490,12 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB + > Close + Details Options + + Start Close B Back === plan-in-place 40x15 RetroBIOS: RetroArch @@ -503,26 +503,24 @@ Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, - the old one kept in a backup folder. - Free space: 50.0 GB > Close + Details Options + + + Start Close B Back === plan-in-place 80x24 RetroBIOS: RetroArch Every file on the list is in place BIOS folder: ~/.config/retroarch/system - 5 in place, 0 missing, 0 wrong copies - 1 of the 0 wrong copies is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Close + Details Options @@ -537,6 +535,8 @@ + + Start Close B Back === systems 40x12 RetroBIOS: Choose systems @@ -866,39 +866,37 @@ RetroBIOS: Confirm Counted again for these choices. - Nothing is written before Install. 1 file to download, 16.0 KB BIOS folder: ~/.co.../retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back + + + Start Install B Back === confirm 40x15 RetroBIOS: Confirm Counted again for these choices. - Nothing is written before Install. 1 file to download, 16.0 KB BIOS folder: ~/.co.../retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back + + + Start Install B Back === confirm 80x24 RetroBIOS: Confirm - Counted again for these choices. Nothing is written before Install. + Counted again for these choices. 1 file to download, 16.0 KB BIOS folder: ~/.config/retroarch/system - 0 in place, 1 missing, 0 wrong copies - Free space: 50.0 GB > Install Back @@ -915,6 +913,8 @@ + + Start Install B Back === installing 40x12 RetroBIOS: Installing @@ -926,7 +926,7 @@ B stops. What is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + B Stop === installing 40x15 @@ -939,7 +939,7 @@ B stops. What is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + @@ -955,7 +955,7 @@ B stops. What is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + @@ -976,12 +976,12 @@ 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/ retrobios-backup/2026-10-23_1200 - Details: /tmp/retrobios-x/install.log + Log: /tmp/retrobios-x/install.log + Start Exit === result 40x15 RetroBIOS: Finished with errors @@ -989,12 +989,12 @@ 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/ retrobios-backup/2026-10-23_1200 - Details: /tmp/retrobios-x/install.log + Log: /tmp/retrobios-x/install.log + @@ -1004,11 +1004,11 @@ 3 installed, 1 failed. BIOS folder: /home/user/.config/retroarch/system - failed: scph5500.bin (HTTP 404) Run it again to retry only those. The files it replaced are kept in /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200 - Details: /tmp/retrobios-x/install.log + Log: /tmp/retrobios-x/install.log + @@ -1138,12 +1138,12 @@ D-pad, Up/Down Move Start, Enter Install o, Tab Options + d Details B, Esc, Backspace Back q, Ctrl-C Quit Select Keyboard on or off Menu Close the terminal - Any key closes this help === help 40x15 RetroBIOS: Keys @@ -1151,6 +1151,7 @@ D-pad, Up/Down Move Start, Enter Install o, Tab Options + d Details B, Esc, Backspace Back q, Ctrl-C Quit Select Keyboard on or off @@ -1159,7 +1160,6 @@ BIOS folder: /home/user/.config/retroarch/system - Any key closes this help === help 80x24 RetroBIOS: Keys @@ -1167,6 +1167,7 @@ D-pad, Up/Down Move Start, Enter Install o, Tab Options + d Details B, Esc, Backspace Back q, Ctrl-C Quit Select Keyboard on or off @@ -1184,7 +1185,6 @@ - Any key closes this help === plan-games 40x12 RetroBIOS: RetroArch @@ -1197,7 +1197,7 @@ For the games on this card: yes 412 Only what starts: no Show the games - 1-4 of 8 + 1-4 of 9 Start Install B Back === plan-games 40x15 RetroBIOS: RetroArch @@ -1205,13 +1205,13 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system - For the 412 games on this card. > Install For the games on this card: yes 412 Only what starts: no Show the games Choose systems Copy from an old card or a folder + Details Options Quit Start Install B Back @@ -1221,11 +1221,6 @@ 4 files to download, 1.0 MB BIOS folder: ~/.config/retroarch/system For the 412 games on this card. - One region where the games prove it: nintendo-gba Europe. - 2 games get every BIOS of their system: Show the games. - 1 in place, 3 missing, 1 wrong copy - The 1 wrong copy is replaced, the old one kept in a backup folder. - Free space: 50.0 GB > Install For the games on this card: yes 412 games @@ -1233,12 +1228,17 @@ Show the games Choose systems Copy the BIOS files from an old card or a folder + Details Options Quit + + + + Start Install B Back === games 40x12 RetroBIOS: Games on this card @@ -1293,4 +1293,112 @@ + Start Back +=== plan-details 40x12 + RetroBIOS: Details + + 1 in place, 3 missing, 1 wrong copy + The 1 wrong copy is replaced, the old + one kept in a backup folder. + Free space: 50.0 GB + + + + + + Start Back +=== plan-details 40x15 + RetroBIOS: Details + + 1 in place, 3 missing, 1 wrong copy + The 1 wrong copy is replaced, the old + one kept in a backup folder. + Free space: 50.0 GB + + + + + + + + + Start Back +=== plan-details 80x24 + RetroBIOS: Details + + 1 in place, 3 missing, 1 wrong copy + The 1 wrong copy is replaced, the old one kept in a backup folder. + Free space: 50.0 GB + + + + + + + + + + + + + + + + + + + Start Back +=== result-details 40x12 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + + + + + + + + + Start Back +=== result-details 40x15 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + + + + + + + + + + + + Start Back +=== result-details 80x24 + RetroBIOS: Details + + failed: scph5500.bin (HTTP 404) + + + + + + + + + + + + + + + + + + + + Start Back diff --git a/tests/test_doc_pages.py b/tests/test_doc_pages.py index bcfda2ef0..d8a558358 100644 --- a/tests/test_doc_pages.py +++ b/tests/test_doc_pages.py @@ -187,7 +187,7 @@ class InstallerSamplesSayWhatTheCodePrints(unittest.TestCase): page = _page("installer.md") refused = _generated(page, "check-refused") - self.assertRegex(refused, r"\n \d+ files? [a-z ]+:\n") + self.assertRegex(refused, r"\n \d+ files? [a-z ]+\.\n") self.assertIn("read by beetle_psx, pcsx_rearmed at", refused) self.assertNotRegex(page, r"opened at /\S+ by ") self.assertIn('"read by ', inspect.getsource(install.opened_line)) diff --git a/tests/test_install.py b/tests/test_install.py index eba661cfa..41e7aab15 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -5668,7 +5668,7 @@ class RunsAgainstTheRealLists(unittest.TestCase, _LoopbackRun): proc = _install_run(self.env, "--platform", "retroarch", "--dest", str(dest), "--check", "--no-input", "--verbose") self.assertEqual(proc.returncode, 3, proc.stderr) - listing = proc.stdout.split("to download:\n", 1)[1].splitlines() + listing = proc.stdout.split("to download.\n", 1)[1].splitlines() self.assertEqual(listing[0].strip(), "wrong copy: scph5501.bin") def test_a_dry_run_counts_the_data_trees_and_ends_on_its_last_line(self): @@ -5716,7 +5716,7 @@ class RunsAgainstTheRealLists(unittest.TestCase, _LoopbackRun): "--manifest", str(REPO_ROOT / "install" / "retroarch.json")) self.assertEqual(proc.returncode, 3, proc.stdout + proc.stderr) missing = re.search(r"0 in place, (\d+) missing", proc.stdout).group(1) - self.assertIn(f"\n {missing} files not in place:\n", proc.stdout) + self.assertIn(f"\n {missing} files not in place.\n", proc.stdout) self.assertIn(f" {missing} files need the internet", proc.stdout) def test_a_cores_folder_can_be_named(self): diff --git a/tests/test_install_tui.py b/tests/test_install_tui.py index 785e379f8..b0aaa73ce 100644 --- a/tests/test_install_tui.py +++ b/tests/test_install_tui.py @@ -83,6 +83,11 @@ def keys(*names: str) -> list: return [Key("char", name[5:]) if name.startswith("char:") else Key(name) for name in names] +# The screens as --verbose draws them, every Details line where it belongs: +# the findings marked with it read lines the default leaves to Details. +in_full = mock.patch.object(install, "tui_verbose", lambda _state: True) + + def _args(**given) -> argparse.Namespace: """The namespace main() parses, every option at its default.""" values = dict( @@ -1002,19 +1007,7 @@ def golden_states() -> dict: "bytes_total": 1064964} installing.finished = [("gba_bios.bin", True, ""), ("scph5500.bin", False, "HTTP 404")] states["installing"] = installing - result = checked_state() - result.stack.append("result") - result.code = 1 - result.log = "/tmp/retrobios-x/install.log" - result.download = installing.download - result.summary = { - "event": "summary", "mode": "install", "installed": 3, "up_to_date": 1, "pending": 1, - "failed": [{"dest": "scph5500.bin", "reason": "HTTP 404"}], - "skipped": [{"reason": "not_found", "label": "not found", "files": 2, "required": 1}], - "left_out": [], "kept": [{"folder": str(HOME / ".config/retroarch/retrobios-backup/" - "2026-10-23_1200"), "files": 1, "bytes": 4}], - "interrupted": False} - states["result"] = result + states["result"] = golden_states_result() error = fresh_state() error.stack, error.run = ["setup", "error"], "check" error.error = [" Could not fetch the file list for retroarch after 3 attempts: " @@ -1032,9 +1025,33 @@ def golden_states() -> dict: listed = games_state() listed.stack.append("games") states["games"] = listed + # What the plan and the result leave out by default, one press away. + details = checked_state() + details.stack.append("details") + states["plan-details"] = details + told = golden_states_result() + told.stack.append("details") + states["result-details"] = told return states +def golden_states_result() -> install.TuiState: + """The result golden_states draws, a file failed and one kept.""" + result = checked_state() + result.stack.append("result") + result.code = 1 + result.log = "/tmp/retrobios-x/install.log" + result.download = {"event": "download", "files": 4, "bytes": 1064964} + result.summary = { + "event": "summary", "mode": "install", "installed": 3, "up_to_date": 1, "pending": 1, + "failed": [{"dest": "scph5500.bin", "reason": "HTTP 404"}], + "skipped": [{"reason": "not_found", "label": "not found", "files": 2, "required": 1}], + "left_out": [], "kept": [{"folder": str(HOME / ".config/retroarch/retrobios-backup/" + "2026-10-23_1200"), "files": 1, "bytes": 4}], + "interrupted": False} + return result + + def result_states() -> dict: """The result of a run that installed everything, of one with a file failed, of one --offline left files out of, and of one stopped.""" @@ -1159,8 +1176,11 @@ class Views(unittest.TestCase): def test_each_role_paints_a_status_word_on_the_result_screens(self): """Done, a part done, files left offline, a stop: between them the result screens use every role, each on a word that says it.""" + # The failed files are listed on the result's Details. + told = result_states()["partial"] + told.stack.append("details") drawn = "\n".join(install.tui_paint(str(line), line.style, True) - for state in result_states().values() + for state in [*result_states().values(), told] for line in install.tui_view(state, 80, 24)) for role, word in (("accent", "RetroBIOS"), ("strong+success", "4 files installed"), ("strong+success", "Done"), ("failure", "1 failed"), @@ -1573,6 +1593,7 @@ class SmallFixes(unittest.TestCase): self.assertTrue(state.installed_only) self.assertNotIn("--installed-cores", [f for f, _v in install.tui_flags(state)]) + @in_full def test_the_end_of_a_wrapped_pager_is_reachable(self): state = checked_state() state.stack.append("result") @@ -2081,7 +2102,7 @@ class WorkFolders(unittest.TestCase): def test_a_failure_keeps_the_log_it_names(self): work, out = self.run_to(1) self.assertTrue(work.exists()) - self.assertIn(f"Details: {work / 'install.log'}", out) + self.assertIn(f"Log: {work / 'install.log'}", out) def test_a_stop_leaves_nothing(self): work, out = self.run_to(130) @@ -2238,6 +2259,7 @@ class CopyFromAnOldCard(unittest.TestCase): self.assertEqual(state.from_folders, [Path("/media/old")]) self.assertIn(("--from", "/media/old"), install.tui_flags(state)) + @in_full def test_files_in_the_wrong_place_are_said_and_listed(self): state = checked_state() state.platform, state.dest = "retroarch", SYSTEM_DIR @@ -2778,6 +2800,7 @@ class CardsSpaceAndConfirm(unittest.TestCase): if row.action == "game_data") self.assertEqual(label, "Game data: left out") + @in_full def test_the_plan_says_which_config_named_the_folder(self): config = HOME / ".config/retroarch/retroarch.cfg" with mock.patch.dict(install._RETROARCH_CONFIGS, {SYSTEM_DIR: (config, config.parent)}): @@ -2803,6 +2826,7 @@ class CardsSpaceAndConfirm(unittest.TestCase): # 1 MB from the network in 2 s, whatever came from the old card. self.assertIn("512.0 KB/s, 0:02 left", text) + @in_full def test_the_plan_says_what_the_scan_left_out(self): state = checked_state() state.from_folders = [Path("E:\\")] @@ -3009,6 +3033,7 @@ class SaveDirectoryLeftOut(unittest.TestCase): install.tui_receive(state, ("ended", state.run_id, 1, [])) return state, summary + @in_full def test_a_list_that_holds_none_of_them_offers_no_folder(self): """RetroPie's list leaves its save files out with no hash or address: --save-dir installs none of them, and was advised again each run.""" @@ -3024,6 +3049,7 @@ class SaveDirectoryLeftOut(unittest.TestCase): self.assertEqual([text for text in install.tui_outcome(state)[1] if "save" in text], [line]) + @in_full def test_files_left_out_of_the_save_directory_are_said(self): state = fresh_state() state.stack = ["setup"] @@ -3673,6 +3699,7 @@ class DataFilesHaveASize(unittest.TestCase): """"8179 files to download, 6.6 GB, and 2636 data files", the data files with no size.""" + @in_full def test_the_plan_gives_the_data_files_size(self): state = fresh_state() state.stack = ["setup"] @@ -3720,6 +3747,7 @@ class ThePagerCountsLines(unittest.TestCase): self.assertTrue(any(re.fullmatch(rf" \d+-{len(wrapped)} of {len(wrapped)}", line) for line in body), body) + @in_full def test_the_counter_moves_one_line_per_press(self): state = self.result_state(40, 12) first = [line for line in install.tui_view(state, 40, 12) if " of " in line][-1] @@ -3862,6 +3890,7 @@ class BackTicksAndSaveFolder(unittest.TestCase): state = install.TuiState() self.assertLess(abs(state.now - time.monotonic()), 5) + @in_full def test_a_pack_installs_from_the_pack(self): state = checked_state() state.found = [{"event": "found", "platform": "retroarch", "dest": FILES[0]["dest"], @@ -4152,6 +4181,7 @@ class TheSaveFolderLineFollowsTheChoice(unittest.TestCase): self.assertEqual(state.screen, "result") self.assertNotIn("save directory", self.said(install.tui_outcome(state)[1])) + @in_full def test_kept_the_confirm_screen_and_the_result_name_it(self): state = self.run_to_result(confirm_saves=True, install_saves=True) self.assertIn(self.LINE, self.confirm) @@ -4882,6 +4912,11 @@ class EndToEnd(unittest.TestCase): screen = term.wait("RetroBIOS is on the KNULLI card") self.assertIn("start RetroBIOS from Ports", screen) self.assertNotIn(install.APP_OFFER, screen) + # The command, a Details line, is said after Exit once they were opened. + term.send("d") + term.wait("RetroBIOS: Details") + term.send("\x1b") + term.wait("RetroBIOS is on the KNULLI card") term.send("\r") self.assertEqual(term.close(), 0) self.assertAppOnCard(root, "KNULLI") @@ -4904,7 +4939,9 @@ class EndToEnd(unittest.TestCase): after = term.after() self.assertIn("RetroBIOS: Done", after) self.assertIn("5 files installed.", after) - self.assertIn("--platform retroarch --dest", after) + # The command is a Details line: said after Exit once they were opened. + self.assertIn("Next: start RetroArch and play.", after) + self.assertNotIn("--platform retroarch --dest", after) # The cursor and the main screen come back before the result is printed. self.assertIn(b"\x1b[?25h\x1b[?1049l", term.raw) @@ -4943,15 +4980,24 @@ class EndToEnd(unittest.TestCase): term.send("\r") screen = term.wait("files to download") self.assertIn("6 files to download", screen) - # The second folder the run writes to, named before - # anything is written, and again on the result. + # The second folder the run writes to, named on the + # plan's Details before anything is written, and on the + # result's. + term.send("d") + screen = term.wait("RetroBIOS: Details") self.assertIn("1 file read from RetroArch's save directory goes to a " "folder per core under:\n ~/MySaves", screen) + term.send("\x1b") + term.wait("files to download") term.send("\r") - screen = term.wait("6 files installed.") + term.wait("6 files installed.") + term.send("d") + screen = term.wait("RetroBIOS: Details") # Spelled in full on the result, as its other folders. joined = "".join(line.strip() for line in screen.splitlines()) self.assertIn("folder per core under:" + str(saves), joined) + term.send("\x1b") + term.wait("6 files installed.") term.send("\r") self.assertEqual(term.close(), 0) results.append(written(repo, saves)) @@ -4978,6 +5024,10 @@ class EndToEnd(unittest.TestCase): self.assertIn("3 files to download", screen) term.send("\r") term.wait("3 files installed.") + term.send("d") + term.wait("RetroBIOS: Details") + term.send("\x1b") + term.wait("3 files installed.") term.send("\r") self.assertEqual(term.close(), 0) self.assertEqual(repo.installed(), ["pcsx/extra.bin", "scph5500.bin", "scph5501.bin"]) @@ -4999,9 +5049,13 @@ class EndToEnd(unittest.TestCase): screen = term.wait("4 files to download") self.assertIn("> Install", screen) term.send("\r") - screen = term.wait("installed.") + term.wait("installed.") + term.send("o") + screen = term.wait("RetroBIOS: Details") self.assertIn("1 game data file left out.", screen) term.send("\r") + term.wait("installed.") + term.send("\r") self.assertEqual(term.close(), 0) self.assertEqual(repo.installed(), ["gba_bios.bin", "mgba/extra.bin", "pcsx/extra.bin", "scph5501.bin"]) @@ -5090,6 +5144,10 @@ class EndToEnd(unittest.TestCase): self.assertIn("5 files installed.", screen) self.assertIn("3 files copied from", screen) self.assertIn("2 downloaded.", screen) + term.send("o") + term.wait("RetroBIOS: Details") + term.send("\r") + term.wait("files installed.") term.send("\r") self.assertEqual(term.close(), 0) self.assertEqual(len(repo.installed()), 5) @@ -5808,6 +5866,7 @@ class ThePlanNumbersAddUp(unittest.TestCase): """"47 files to download" sat above "49 missing, 1 wrong copy": the 3 found on this machine were the difference, left to the reader.""" + @in_full def test_the_copied_files_are_the_difference(self): state = checked_state() state.found = [found("scph5500.bin", str(SYSTEM_DIR), "one folder too deep")] @@ -6441,6 +6500,7 @@ class ConfirmRefusalsAndCardRows(unittest.TestCase): if row.action == "platform"} self.assertEqual(labels["knulli"], "KNULLI") + @in_full def test_offline_plan_counts_agree(self): """"3 downloaded" under "3 need the internet"; the data files read as if on hand.""" @@ -6871,6 +6931,7 @@ class WhatEachScreenOffers(unittest.TestCase): rows = install.tui_rows(state) self.assertEqual(rows[state.focus["browse"]].value, stick) + @in_full def test_offline_plan_names_the_folder_already_copied_from(self): state = checked_state() state.from_folders = [self.root / "from1"] @@ -6979,6 +7040,7 @@ class WhatEachScreenOffers(unittest.TestCase): "not known. Name it with --save-dir next time.", text) self.assertNotIn("the collection does not hold", text) + @in_full def test_plural_game_data_and_the_backup_line_at_40x12(self): state = checked_state() games = [{"dest": f"g{index}.dat", "system": "", "category": install.GAME_DATA} @@ -7759,6 +7821,7 @@ class LineModeAndScreenDecideAlike(_LineModeFindings, _OutsideTextFindings, self.assertIn("1 game data file left out (--no-game-data)", after) self.assertNotIn("doom1.wad would", after) + @in_full def test_the_plan_counts_game_data_apart_and_one_press_leaves_it_out(self): state = checked_state() manifest = json.loads(json.dumps(state.manifest)) @@ -7890,6 +7953,7 @@ class LineModeAndScreenDecideAlike(_LineModeFindings, _OutsideTextFindings, if split: self.assertEqual(int(split[1]) + int(split[2]), int(head[1])) + @in_full def test_the_screen_divides_the_count_it_shows(self): state = checked_state() manifest = json.loads(json.dumps(state.manifest)) @@ -9017,6 +9081,7 @@ class PacksWordingAndDocs(unittest.TestCase): install.LOCAL.pack = mock.Mock(name="pack") self.assertIn("to install from the pack", install._pager_items(state)[0]) + @in_full def test_scroll_is_named_only_where_the_text_scrolls(self): """"Up/Down Scroll" over nine lines that fit.""" state = checked_state() @@ -10082,6 +10147,7 @@ class CardNamesAndHelp(_CardFixtures, unittest.TestCase): self.assertNotIn("A/Enter", bar) self.assertNotIn("B/Esc", bar) + @in_full def test_the_folder_its_config_named_is_said_under_it(self): state = checked_state() long_dest = Path("/home/user/" + "a-long-folder-name/" * 5 + "system") @@ -10227,6 +10293,7 @@ class TheAndroidResultReadsWhole(unittest.TestCase): state.cols, state.rows = cols, 40 return install.tui_view(state, cols, 40) + @in_full def test_a_path_or_a_command_is_never_split_inside_a_word(self): full = "/sdcard/RetroArch/retrobios-backup/20261027-223524" for cols in (40, 50, 80): @@ -10948,6 +11015,7 @@ class TapsGameDataAndExitCodes(_CardFixtures, unittest.TestCase): plain.help = True self.assertNotIn("Tap", " ".join(install.tui_view(plain, 80, 24))) + @in_full def test_the_result_is_left_by_a_tap(self): """The result gave the mouse back, and on Termux leaving it took the keyboard. A tap on its Exit closes it, and its @@ -10964,6 +11032,7 @@ class TapsGameDataAndExitCodes(_CardFixtures, unittest.TestCase): # Root cause 2: one narrowed list drives every count. + @in_full def test_the_game_data_row_and_the_save_line_follow_the_choice(self): """With only the GBA ticked, the plan said 1 game data file and a save file of the PlayStation.""" @@ -11001,6 +11070,7 @@ class TapsGameDataAndExitCodes(_CardFixtures, unittest.TestCase): word = "left out" if left else "kept" self.assertRegex(line, rf"^ Game data: {word} +51(, | files, )2\.4 GB$") + @in_full def test_data_files_are_named_apart(self): """Data files beside BIOS files and game data, the parts adding up to the count above, each kind said once.""" @@ -11013,6 +11083,7 @@ class TapsGameDataAndExitCodes(_CardFixtures, unittest.TestCase): "other cores. Data files: the files an emulator reads from a data " "folder of its own, such as Dolphin's Sys and PPSSPP's assets.", text) + @in_full def test_confirm_counts_the_kinds_apart(self): """Extra criteria: the plan split BIOS files and game data, Confirm did not.""" @@ -11292,6 +11363,7 @@ class TapsGameDataAndExitCodes(_CardFixtures, unittest.TestCase): rows = install.tui_rows(state) self.assertIn(sides[0][1], [row.value for row in rows if row.action == "drive"]) + @in_full def test_named_by_sits_under_its_folder(self): """The offline remedy and the narrowing came between the folder and what named it.""" @@ -11421,7 +11493,7 @@ class TapsOnAPty(unittest.TestCase): bar = term.screen.display[-1] self.click(term, bar.index("Exit"), len(term.screen.display) - 1) self.assertEqual(term.close(), 0) - self.assertIn("Same choice without questions:", term.after()) + self.assertIn("Next: start RetroArch and play.", term.after()) self.assertGreater(term.raw.rfind(b"\x1b[?1000l"), mark) @@ -11742,6 +11814,7 @@ class OneChoicePerRun(unittest.TestCase): state.exit_code, state.quit_asked = install.QUIT_CODE, True self.assertIn(note, install.tui_farewell(state)) + @in_full def test_the_help_defines_game_data_at_40_columns(self): """The row was a choice nothing explained on the Miyoo's screen.""" @@ -11807,6 +11880,7 @@ class OneChoicePerRun(unittest.TestCase): whole="command") self.assertIn(f" --from-pack {path}", lines) + @in_full def test_the_definition_is_said_once_and_never_spliced(self): state = checked_state() state.systems = [] @@ -11819,6 +11893,7 @@ class OneChoicePerRun(unittest.TestCase): self.assertIn("Not available here: jazz2/Source/Anims.j2a (Jazz Jackrabbit 2), game " "data its game reads.", text) + @in_full def test_the_headline_counts_every_file_once(self): """"8358 files and 2636 data files", and the definition dropped at 80 columns.""" @@ -11830,6 +11905,7 @@ class OneChoicePerRun(unittest.TestCase): self.assertNotIn("and 7 data files", lines[2]) self.assertIn("Data files: the files an emulator reads", text) + @in_full def test_the_save_line_never_ends_on_its_colon(self): """"...goes to a folder per core under:" with no folder at 60x20.""" @@ -11927,6 +12003,7 @@ class OneChoicePerRun(unittest.TestCase): said = " ".join(install._needed_lines(entries, "Needed")) self.assertIn("... and 1 more system (--check --verbose lists them all)", said) + @in_full def test_the_farewell_names_the_option_not_the_screen(self): state = _installed_state(SYSTEM_DIR) state.manifest = {**state.manifest, "save_directory": {"folder": "saves", @@ -12674,6 +12751,7 @@ class ChoiceStateInBothModes(unittest.TestCase): _title, lines = install.tui_outcome(state) self.assertIn("7 data files not installed: not in RetroArch_BIOS_Pack.zip.", lines) + @in_full def test_a_command_at_40_columns_breaks_between_shell_words(self): """The terminal folded commands inside a word, "--platform" ended a line with its value on the next.""" @@ -12707,6 +12785,7 @@ class ChoiceStateInBothModes(unittest.TestCase): farewell = "\n".join(install.tui_farewell(state)) self.assertIn("/home/moi/retroarch_system/tmp/tui_audit14/sb/a/b/bios", farewell) + @in_full def test_a_folder_on_its_own_line_has_one_indent(self): """The save folder at the label's indent, the BIOS folder under it, a path's last piece without its indent.""" @@ -13341,6 +13420,7 @@ class OneVocabularyOneCount(unittest.TestCase): self.assertIn("1 in place, 3 missing, 0 wrong copies", text) self.assertIn("Nothing installed: 3 files need the internet", text) + @in_full def test_a_pack_holding_none_offers_no_install(self): """A data tree whose folder is the BIOS folder itself (blueMSX) made any pack hold a data file: Install focused, @@ -13533,6 +13613,7 @@ class TheFromPlanSaysItsKinds(unittest.TestCase): """Every file found in the folder, the plan named the Game data row and said neither the kinds nor what game data is.""" + @in_full def test_the_kinds_and_the_definition_stay(self): audit = OneChoicePerRun() state = audit.game_plan() @@ -14542,6 +14623,7 @@ class CoresListAndFolderFailures(unittest.TestCase): # Root cause 6: every other item. + @in_full def test_offline_the_plan_promises_no_replacement_it_cannot_make(self): """Offline, the plan said a wrong copy no folder holds "is replaced".""" @@ -14668,6 +14750,7 @@ class GamesOnTheCard(unittest.TestCase): """For the games on this card: the first choice where the card holds games, the whole list one press away (--for-games).""" + @in_full def test_a_card_with_games_opens_on_them(self): state = games_state() self.assertTrue(state.for_games) @@ -14845,5 +14928,149 @@ class GamesEndToEnd(unittest.TestCase): written = sorted(p.name for p in card.bios.rglob("*") if p.is_file()) self.assertEqual(written, ["bios_CD_E.bin", "cd_extra.bin"]) +# The most words each screen may show by default, one count per size of +# SIZES (owner, 2026-11-09: a beginner lost the important line in text). A +# path is no word. The plan, Confirm and the result say what happens, where +# and what next; their counts, notes and commands wait on Details. A list +# shows more rows on a taller window. A change that adds words to a screen +# raises its numbers here and says why. +SCREEN_WORDS = { + "setup": (29, 36, 34, 34), "platforms": (23, 27, 89, 225), "folder": (27, 27, 25, 25), + "folder-card": (52, 52, 50, 50), "browse": (17, 17, 15, 15), "path": (23, 23, 25, 25), + "create": (23, 23, 21, 21), "checking": (18, 18, 17, 17), "plan": (31, 31, 31, 31), + "plan-in-place": (22, 22, 19, 19), "systems": (36, 37, 36, 36), + "options": (40, 42, 59, 59), "regions": (45, 44, 42, 42), "cores": (47, 47, 45, 45), + "preview": (29, 29, 28, 28), "command": (22, 22, 16, 16), "confirm": (22, 22, 20, 20), + "installing": (32, 32, 31, 31), "result": (29, 29, 27, 27), "error": (37, 34, 32, 31), + "quit": (14, 14, 12, 12), "help": (24, 26, 26, 26), "plan-games": (36, 46, 54, 54), + "games": (36, 45, 44, 44), "plan-details": (30, 30, 29, 29), + "result-details": (34, 34, 23, 23), +} + + +def screen_words(lines: list) -> int: + """Words of a drawn screen, its title and bar included, a path left out.""" + return sum(1 for line in lines for token in str(line).split() + if re.search(r"[A-Za-z0-9]", token) and "/" not in token) + + +class ScreenWordBudgets(unittest.TestCase): + def setUp(self): + patcher = mock.patch.object(install, "_mounted_cards", return_value=[]) + patcher.start() + self.addCleanup(patcher.stop) + + def test_every_screen_keeps_to_its_budget(self): + states = golden_states() + self.assertEqual(sorted(states), sorted(SCREEN_WORDS), + "a screen without a word budget, or a budget without its screen") + for name, state in states.items(): + for (cols, rows), budget in zip(SIZES, SCREEN_WORDS[name]): + with self.subTest(screen=name, size=f"{cols}x{rows}"): + state.cols, state.rows = cols, rows + words = screen_words(install.tui_view(state, cols, rows)) + self.assertLessEqual(words, budget) + + def test_the_default_path_says_what_where_and_next_first(self): + """The plan opens on what it installs and where, the result on what + happened, where and the next step: nothing between them.""" + plan = [str(line).strip() for line in install.tui_view(checked_state(), 80, 24)] + self.assertEqual(plan[2:4], ["4 files to download, 1.0 MB", + "BIOS folder: ~/.config/retroarch/system"]) + self.assertEqual(plan[4], "") + done = result_states()["done"] + lines = [str(line).strip() for line in install.tui_view(done, 80, 24)] + self.assertEqual(lines[2:5], ["4 files installed. 1 file already in place.", + f"BIOS folder: {SYSTEM_DIR}", + "Next: start RetroArch and play."]) + + +class DetailsScreen(unittest.TestCase): + """What the plan, Confirm and the result leave out by default, one key + or one row away, and every line of --verbose in one place or the other.""" + + def setUp(self): + patcher = mock.patch.object(install, "_mounted_cards", return_value=[]) + patcher.start() + self.addCleanup(patcher.stop) + + def text(self, state: install.TuiState, cols: int = 80, rows: int = 24) -> str: + return "\n".join(str(line) for line in install.tui_view(state, cols, rows)) + + def test_d_opens_the_plans_details_and_b_comes_back(self): + state = checked_state() + self.assertNotIn("Free space", self.text(state)) + press(state, "d") + self.assertEqual(state.screen, "details") + shown = self.text(state) + for line in ("1 in place, 3 missing, 1 wrong copy", "Free space: 50.0 GB", + "The 1 wrong copy is replaced"): + self.assertIn(line, shown) + press(state, "esc") + self.assertEqual(state.screen, "plan") + + def test_a_controller_reaches_them_by_the_row(self): + state = checked_state() + rows = install.tui_rows(state) + state.focus["plan"] = [row.action for row in rows].index("details") + self.assertIn("A/Enter Show", self.text(state)) + press(state, "enter") + self.assertEqual(state.screen, "details") + press(state, "enter") + self.assertEqual(state.screen, "plan") + + def test_the_results_details_are_said_after_exit_once_opened(self): + state = golden_states_result() + self.assertIn("Y/o Details", self.text(state)) + self.assertNotIn("Same choice without questions", "\n".join(install.tui_farewell(state))) + press(state, "o") + self.assertEqual(state.screen, "details") + self.assertIn("Same choice without questions:", self.text(state)) + press(state, "esc") + self.assertEqual(state.screen, "result") + press(state, "enter") + farewell = "\n".join(install.tui_farewell(state)) + self.assertIn("Same choice without questions:", farewell) + self.assertIn("failed: scph5500.bin (HTTP 404)", farewell) + + def test_confirm_has_its_details_too(self): + state = golden_states()["confirm"] + self.assertNotIn("Free space", self.text(state)) + press(state, "d") + self.assertEqual(state.screen, "details") + self.assertIn("Nothing is written before Install.", self.text(state)) + self.assertIn("Free space: 50.0 GB", self.text(state)) + + def test_every_line_is_on_the_screen_or_its_details(self): + """The screen and its Details together say what --verbose says on + the screen alone: no line is lost.""" + for name in ("plan", "plan-games", "plan-in-place", "confirm", "result"): + with self.subTest(screen=name): + state = golden_states()[name] + whole = (install._plan_text(state) if state.screen == "plan" + else install._confirm_text(state) if state.screen == "confirm" + else install.tui_outcome(state)[1]) + shown = install._shown(state, whole) + state.stack.append("details") + told = install.details_lines(state) + self.assertEqual(sorted(map(str, whole)), + sorted(map(str, [*shown, *[line for line in told + if install._is_detail(line)]]))) + + def test_verbose_draws_them_in_place_and_offers_no_row(self): + state = checked_state() + state.passthrough = [("--verbose", None)] + text = self.text(state) + self.assertIn("Free space: 50.0 GB", text) + self.assertNotIn("details", [row.action for row in install.tui_rows(state)]) + + def test_installing_lists_the_files_that_went_well_with_verbose(self): + state = golden_states()["installing"] + self.assertNotIn("gba_bios.bin", self.text(state)) + self.assertIn("FAILED scph5500.bin (HTTP 404)", self.text(state)) + state.passthrough = [("--verbose", None)] + self.assertIn("ok gba_bios.bin", self.text(state)) + + if __name__ == "__main__": unittest.main() diff --git a/tests/test_no_game_data.py b/tests/test_no_game_data.py index 2bb59c2fc..42a9d571f 100644 --- a/tests/test_no_game_data.py +++ b/tests/test_no_game_data.py @@ -287,7 +287,7 @@ class InstallerLeavesGameDataOut(unittest.TestCase): def test_install_leaves_it_out_and_names_it(self): self.serve() - proc = self.run_installer("--no-game-data") + proc = self.run_installer("--no-game-data", "--verbose") self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr) self.assertTrue((self.bios / "a.bin").exists()) self.assertFalse((self.bios / "game.wad").exists()) @@ -297,10 +297,10 @@ class InstallerLeavesGameDataOut(unittest.TestCase): def test_check_and_dry_run_leave_it_out(self): self.serve() - for mode, listed in (("--check", "1 file to download:"), + for mode, listed in (("--check", "1 file to download."), ("--dry-run", "Would download 1 file")): with self.subTest(mode=mode): - proc = self.run_installer("--no-game-data", mode) + proc = self.run_installer("--no-game-data", mode, "--verbose") self.assertIn( "2 game data files left out (--no-game-data), 1 of them not installable: " "game.wad, level.dat", diff --git a/wiki/installer.md b/wiki/installer.md index 5ce100f68..55c2899a9 100644 --- a/wiki/installer.md +++ b/wiki/installer.md @@ -171,8 +171,9 @@ Enter checks the BIOS folder when nothing can be copied. Run at a terminal, the installer opens a full screen that a keyboard or a controller drives. Three presses of A or Enter install everything the setup reads: the setup found here, the plan, then the result. The plan screen says -how many files are missing, how much they weigh, how many are in place and how -much space is free, before anything is written. +what it installs, its size and where, before anything is written. **Details** +(`d`) adds the rest: how many files are in place, the free space, the files +left out and why. The other choices sit one press away. **Choose systems** ticks the consoles to keep, with the total to download under the list. It opens on its first system, @@ -207,6 +208,7 @@ install starts. | Tick, untick | Space, Right, Left | X, D-pad Right and Left (X alone inside muxterm, Y with muxterm's own keys) | | Back | Esc, Backspace | B, Select (B alone with muxterm's own keys, where Select shows its keyboard) | | Options | `o`, Tab | Y | +| Details | `d`, and `o` or Tab on the result | the Details row, Y on the result | | Filter a long list | `/` then type, Enter on a lone match chooses it | muxterm: Select shows a keyboard. Elsewhere none (the setup list puts the SD cards after RetroArch) | | Keys of the screen | `?`, F1 (F1 alone while typing a filter, where the help lists the keys that do not type) | | | Stop an install | Esc, `q`, Ctrl+C | B, Select+Start (B alone with muxterm's own keys) | @@ -229,11 +231,12 @@ regions screen, Left and Right move the region under the cursor up and down the order of preference. During the download, a stop waits for the files in progress, and a second one stops at once. Select+Start on a handheld ends the installer with a signal (SIGTERM), which stops it the same way. Either way the -result says how many files were installed, and it stays printed in the terminal -once the screen closes, with the command that repeats the run. A run that failed -keeps its log and names it, and every other run leaves nothing behind. A path -on the result is never split inside a word: one longer than the window takes -a line of its own, which the terminal folds. A command breaks only between its +result says how many files were installed and the next step, and it stays +printed in the terminal once the screen closes. Its **Details** hold the +command that repeats the run, printed in the terminal too once they were +opened. A run that failed keeps its log and names it, and every other run +leaves nothing behind. A path on the result is never split inside a word: one +longer than the window takes a line of its own, which the terminal folds. A command breaks only between its arguments, an option kept with its value, each line but the last ending with the continuation its shell reads (a backslash in sh, a backtick in PowerShell), so the lines copied run as one command. Where an option and its path do not fit @@ -315,8 +318,9 @@ them back on every way out, a stop with Ctrl+Z included. On the command line screen, any screen showing a command and the screen where a path is typed, the terminal keeps the mouse, so text is selected, copied and pasted as usual. The result takes taps, so a touch screen can leave it: it is printed again in -the terminal once the screen closes, its commands with it, and its last line -says so. Elsewhere, and on the result, hold Shift while selecting. `--plain` +the terminal once the screen closes, with its commands when its Details were +opened, and the last line of the Details says so. Elsewhere, and on the +result, hold Shift while selecting. `--plain` never asks for clicks. Clicks and taps were checked on 2026-10-27 in xterm, tmux, GNU screen 4.09, Windows Terminal (WSL) and Termux on Android 17. macOS Terminal and iTerm2 are not checked yet, nor the key @@ -618,7 +622,7 @@ against a list of four files: ``` - 3 files to download: + 3 files to download. 2 of these files are in the BIOS folder in the wrong place: a run without --check copies them where the cores open them, and leaves the copies found as they are. wrong copy: scph5501.bin another region: the contents of scph5500.bin (japan)