From 21230a05eb4ba5f6763240c0b1ecf299929dde74 Mon Sep 17 00:00:00 2001 From: Bernardo Magri Date: Sun, 26 Apr 2026 09:21:40 +0100 Subject: [PATCH] feat(installer): review-then-edit loop with field-level re-prompt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the review screen only offered Confirm/Abort, so a typo or wrong-disk choice meant aborting the whole run and starting over (or hand-editing /tmp/nomarchy-install.state.sh). On --resume the situation was worse: every prompt re-runs (each short-circuits when its var is set), the user lands on a review they can't change. review_configuration() now offers Continue / Edit a field / Abort. Edit opens a multi-select of every saved field; chosen fields clear and the next loop iteration in main() re-prompts only those. The LUKS passphrase short-circuits when already set, so editing other fields doesn't re-prompt for it. Net flow change: - Fresh install: same prompts, then review with Edit option (typo fixes without restarting). - --resume: state loads, every prompt skips (vars set), lands straight on review — exactly what the roadmap entry called for. Verified via `bash -n`. Live VM dry-run not exercised in this session. --- docs/ROADMAP.md | 2 +- installer/install.sh | 87 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 73 insertions(+), 16 deletions(-) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index f273a71..6cc2263 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -28,7 +28,6 @@ Guardrails (apply when adding anything): - **Gaming — declarative flathub remote.** `services.flatpak.enable` doesn't ship a declarative remote API in nixpkgs. Either add the `flatpak-managed-install` overlay, write a one-shot systemd unit that runs `flatpak remote-add --if-not-exists flathub …`, or surface the manual step in `nomarchy-welcome`. - **First-run welcome wizard.** Extend `nomarchy-welcome` from a one-shot greeter into a guided picker: theme, panel position, monospace font, "what's a sane home.nix to start with?". Runs once, persists "done" in `state.json`. - **Plymouth theme variants per palette.** Currently one Plymouth theme; could template per-palette so the boot splash matches the active theme. -- **Installer pre-flight resume polish.** If the user Ctrl-Cs mid-install and runs `--resume`, re-show the review screen before re-prompting for any unsaved fields. ### Later (speculative or research-shaped) @@ -124,6 +123,7 @@ Each PR description should reference the row(s) in `docs/SCRIPTS.md` it closes, (Move items here when they land — keep them brief, link the commit/PR.) +- _2026-04-26_ — Installer review-then-edit flow (`installer/install.sh`). Review screen now offers Continue / Edit a field / Abort. Edit opens a multi-select of saved fields; chosen fields clear and the next loop iteration re-prompts only those. Benefits both fresh installs (typo fixes without abort+restart) and `--resume` (lands on review immediately, since the loaded vars short-circuit each prompt). LUKS passphrase is held in memory across loop iterations so re-edits don't re-ask for it. - _2026-04-26_ — `docs/TROUBLESHOOTING.md`. The five most common rebuild errors (option-already-declared, attribute-missing, Stylix target conflict, home-manager `.hm-bak` churn, impermanence path missing) with copy-paste fixes. Linked from `README.md` and `docs/MIGRATION.md`. - _2026-04-26_ — Gaming preset module (`core/system/gaming.nix`). Opt-in `nomarchy.system.gaming.enable` (default false). Wires `programs.steam` (with `remotePlay`/`localNetworkGameTransfers` firewall holes via `mkDefault`), `programs.gamemode`, and `services.flatpak`. Flathub remote and Hyprland window-rule split into separate Next-column rows. - _2026-04-26_ — Accessibility preset module (`core/system/accessibility.nix`). New `nomarchy.system.accessibility.{enable,cursorSize}` options (opt-in, default off — accessibility isn't a hardware-derived signal). Enables `services.gnome.at-spi2-core`, installs Orca, and sets `XCURSOR_SIZE=32` (configurable). Hyprland-side companion (key-repeat slowdown, Orca keybinding, high-contrast palette) split into a new Next-column row. diff --git a/installer/install.sh b/installer/install.sh index e396cf5..2773764 100755 --- a/installer/install.sh +++ b/installer/install.sh @@ -315,6 +315,11 @@ get_luks_passphrase() { return fi + # Already set this session (review-edit loop iterated). Don't re-prompt; + # password isn't persisted across runs but is held in memory until + # execute_installation unsets it. + [[ -n "${LUKS_PASSWORD:-}" ]] && return + section "Disk Encryption" info "Your disk will be encrypted with LUKS2." @@ -741,16 +746,60 @@ review_configuration() { if [[ "$DRY_RUN" == "true" ]]; then info "Dry run: skipping destructive confirmation." - return + return 0 fi nrun gum style --foreground 9 "This will DESTROY all data on $TARGET_DRIVE" echo "" - if ! nrun gum confirm "Proceed with installation?"; then - error "Aborted" - exit 1 - fi + local action + action=$(nrun gum choose --header "Choose:" \ + "Continue with installation" \ + "Edit a field" \ + "Abort") + case "$action" in + "Continue with installation") return 0 ;; + "Edit a field") edit_fields; return 2 ;; + *) error "Aborted"; exit 1 ;; + esac +} + +# Multi-select clear: each cleared field is re-prompted on the next loop +# iteration in main() because every prompt short-circuits when its var is +# non-empty. Hardware clears the cached `nixos-hardware` modules and per-host +# option lines together so they stay consistent. Passwords are never offered +# here — get_luks_passphrase short-circuits when LUKS_PASSWORD is already set, +# so editing a field doesn't re-ask for the LUKS passphrase. +edit_fields() { + section "Edit Fields" + + local choices + choices=$(nrun gum choose --no-limit --header "Pick fields to re-enter (space to select, enter to confirm):" \ + "Drive ($TARGET_DRIVE)" \ + "User and host ($USERNAME @ $HOSTNAME)" \ + "Keymap and locale ($KEYMAP_LAYOUT / $LOCALE)" \ + "Timezone ($TIMEZONE)" \ + "Hardware ($HARDWARE_MODULES)" \ + "Form factor ($FORM_FACTOR)" \ + "Impermanence ($ENABLE_IMPERMANENCE)" \ + "Profiles (${SELECTED_PROFILES:-none})" \ + "Nomarchy rev (${NOMARCHY_REV:-main})") + + [[ -z "$choices" ]] && return + + while IFS= read -r f; do + case "$f" in + "Drive"*) TARGET_DRIVE="" ;; + "User and host"*) USERNAME=""; HOSTNAME="" ;; + "Keymap"*) KEYMAP_LAYOUT=""; KEYMAP_VARIANT=""; LOCALE="" ;; + "Timezone"*) TIMEZONE="" ;; + "Hardware"*) HARDWARE_MODULES=""; NOMARCHY_HW_OPTS="" ;; + "Form factor"*) FORM_FACTOR="" ;; + "Impermanence"*) ENABLE_IMPERMANENCE="" ;; + "Profiles"*) SELECTED_PROFILES="" ;; + "Nomarchy rev"*) NOMARCHY_REV="" ;; + esac + done <<<"$choices" } # ============================================================================ @@ -1291,16 +1340,24 @@ main() { load_state check_environment - select_disk - get_luks_passphrase - configure_user - select_keymap_locale - select_timezone - select_hardware - confirm_form_factor - configure_impermanence - select_profiles - review_configuration + + # Loop: prompts (each skips when its var is set) → review → Continue|Edit. + # On Edit, edit_fields() clears the chosen vars and the next iteration + # re-prompts only those. Continue breaks. --resume lands here with vars + # already loaded, so the first pass goes straight to review. + while true; do + select_disk + get_luks_passphrase + configure_user + select_keymap_locale + select_timezone + select_hardware + confirm_form_factor + configure_impermanence + select_profiles + if review_configuration; then break; fi + done + execute_installation # Skip the reboot prompt on a dry run — nothing to reboot into.