diff --git a/setup/modules/shell-setup.sh b/setup/modules/shell-setup.sh index 7f56634..0bbcaf5 100755 --- a/setup/modules/shell-setup.sh +++ b/setup/modules/shell-setup.sh @@ -12,7 +12,8 @@ # ║ user — must NOT run as root. ║ # ║ ║ # ║ WHAT GETS DEPLOYED: ║ -# ║ ~/.bashrc, ~/.zshrc — symlinks to Dotfiles repo ║ +# ║ ~/.bashrc, ~/.zshrc, ~/.vimrc — symlinks to Dotfiles repo, unless ║ +# ║ MARCHY_DEPLOY_SHELL_RC=0 (defaults to 1 outside the TUI installer) ║ # ║ ~/.config/starship.toml — symlink to repo ║ # ║ ~/.config/nvim/ — symlink to repo/nvim/ ║ # ║ ~/.config/micro/ — copy from repo/micro/ (plugin state needs cp)║ @@ -160,9 +161,18 @@ if [[ -e "$HOME/.config" && ! -w "$HOME/.config" ]]; then sudo chown -R "$(id -un):$(id -gn)" "$HOME/.config" 2>/dev/null || true fi -# Shell init files — symlink so edits in the repo apply immediately -ln -sf ~/Dotfiles/.bashrc ~/.bashrc -ln -sf ~/Dotfiles/.zshrc ~/.zshrc +# Shell init files — symlink so edits in the repo apply immediately. +# MARCHY_DEPLOY_SHELL_RC lets the caller install the shell tools/plugins below +# (zsh, oh-my-zsh, neovim, yazi, micro, starship, …) without overwriting the +# user's existing .bashrc/.zshrc/.vimrc with the_miro's personal versions. +# Defaults to deploying them when run standalone (outside the TUI installer). +if [[ "${MARCHY_DEPLOY_SHELL_RC:-1}" == "1" ]]; then + ln -sf ~/Dotfiles/.bashrc ~/.bashrc + ln -sf ~/Dotfiles/.zshrc ~/.zshrc + ln -sf ~/Dotfiles/.vimrc ~/.vimrc +else + skip "Personal shell rc's not selected — leaving .bashrc/.zshrc/.vimrc as-is." +fi # Starship prompt config — symlink into ~/.config/ ln -sf ~/Dotfiles/starship.toml ~/.config/starship.toml diff --git a/setup/tools/generate-answerfile.sh b/setup/tools/generate-answerfile.sh index d952c62..6acdc70 100755 --- a/setup/tools/generate-answerfile.sh +++ b/setup/tools/generate-answerfile.sh @@ -201,7 +201,6 @@ dialog --backtitle "$BACKTITLE" \ AF_COMPONENTS="" AF_DE="none" AF_APPS="" -AF_SHELL_RC="dotfiles" AF_COLOR_TEXT="" AF_COLOR_BG="" AF_COLOR_HIGHLIGHT="" @@ -324,14 +323,6 @@ if [[ "$AF_RUN_TUI" == "true" ]]; then 3>&1 1>&2 2>&3) || AF_APPS="" # END GENERATED MODULES: module-checklist - # ── Shell RC preference ─────────────────────────────────────────────────── - AF_SHELL_RC=$(dialog --backtitle "$BACKTITLE" \ - --title " Shell Config for New Users " \ - --menu "\n Should new users on this machine inherit the dotfiles' rc files?\n (Controls what gets copied to /etc/skel)\n" 13 68 2 \ - "dotfiles" "Use the_miro's .zshrc / .bashrc / .vimrc from dotfiles" \ - "defaults" "Skip — use system defaults for new users" \ - 3>&1 1>&2 2>&3) || AF_SHELL_RC="defaults" - # ── Colorway ────────────────────────────────────────────────────────────── # Read defaults from repo colors.conf declare -A _cdef @@ -393,7 +384,6 @@ SUMMARY+=" Encrypt: $AF_ENCRYPT\n" SUMMARY+=" FIDO2 root: $AF_FIDO2_ROOT / FIDO2 user: $AF_FIDO2_USER\n" SUMMARY+=" Run TUI: $AF_RUN_TUI\n" [[ -n "$AF_DE" && "$AF_DE" != "none" ]] && SUMMARY+=" DE: $AF_DE\n" -SUMMARY+=" Shell rc: $AF_SHELL_RC\n" [[ -n "$AF_COLOR_TEXT" ]] && SUMMARY+=" Colors: custom\n" dialog --backtitle "$BACKTITLE" \ @@ -435,8 +425,7 @@ mkdir -p "$(dirname "$OUTPUT")" printf ' "run_tui": %s,\n' "$AF_RUN_TUI" printf ' "components": %s,\n' "$(_words_to_json_array "$AF_COMPONENTS")" printf ' "desktop_environment": %s,\n' "$(json_str "$AF_DE")" - printf ' "apps": %s,\n' "$(_words_to_json_array "$AF_APPS")" - printf ' "shell_rc": %s' "$(json_str "$AF_SHELL_RC")" + printf ' "apps": %s' "$(_words_to_json_array "$AF_APPS")" if [[ -n "$AF_COLOR_TEXT" ]]; then printf ',\n "colors": {\n' diff --git a/setup/tui-install.sh b/setup/tui-install.sh index bb03e78..5c141eb 100755 --- a/setup/tui-install.sh +++ b/setup/tui-install.sh @@ -257,6 +257,18 @@ log_sep() { printf "\n══════════════════════════════════\n %s\n %s\n" "$1" "$(date)" >> "$LOG" } +flush_tty_input() { + # Discard any keystrokes queued on the terminal before the first prompt. + # This script normally runs right after the long, mostly-unattended base + # install (partitioning, pacstrap, …); impatient Enter presses or other + # stray input typed during that wait sit in the tty's input buffer and + # would otherwise be consumed by the very first `read` here — making the + # first checklist appear to auto-confirm its defaults before the user can + # toggle anything. A short non-blocking drain loop clears the queue. + local junk + while read -r -t 0.05 junk /dev/null; do :; done +} + run_module() { local label="$1" script="$2" STEP=$(( STEP + 1 )) @@ -307,13 +319,14 @@ count_steps() { # run_module() can display accurate [N/TOTAL] progress from the first step. # Each glob test mirrors the corresponding run_module() call below; they # must stay in sync whenever a new module is added or removed. - local c="$1" de="$2" a="${3:-}" + local c=" $1 " de="$2" a="${3:-}" TOTAL=0 # Base components: each keyword maps to exactly one module script. - [[ "$c" == *"pkg"* ]] && TOTAL=$(( TOTAL + 1 )) - [[ "$c" == *"core"* ]] && TOTAL=$(( TOTAL + 1 )) - [[ "$c" == *"svc"* ]] && TOTAL=$(( TOTAL + 1 )) - [[ "$c" == *"shell"* ]] && TOTAL=$(( TOTAL + 1 )) + # Padded with spaces so "shell" doesn't false-match the "shellrc" tag. + [[ "$c" == *" pkg "* ]] && TOTAL=$(( TOTAL + 1 )) + [[ "$c" == *" core "* ]] && TOTAL=$(( TOTAL + 1 )) + [[ "$c" == *" svc "* ]] && TOTAL=$(( TOTAL + 1 )) + [[ "$c" == *" shell "* ]] && TOTAL=$(( TOTAL + 1 )) # A non-"none" DE selection always installs exactly one DE module. [[ "$de" != "none" ]] && TOTAL=$(( TOTAL + 1 )) # Optional app modules: one word-boundary check per app, one increment per match. @@ -410,7 +423,6 @@ count_steps() { AF_COMPONENTS="" AF_DE="none" AF_APPS="" -AF_SHELL_RC="dotfiles" AF_COLOR_TEXT="" AF_COLOR_BG="" AF_COLOR_HIGHLIGHT="" @@ -427,7 +439,6 @@ load_answerfile() { AF_COMPONENTS=$(jq -r '(.components // []) | join(" ")' "$ANSWERFILE") AF_DE=$(jq -r '.desktop_environment // "none"' "$ANSWERFILE") AF_APPS=$(jq -r '(.apps // []) | join(" ")' "$ANSWERFILE") - AF_SHELL_RC=$(jq -r '.shell_rc // "dotfiles"' "$ANSWERFILE") # Color values are optional; an empty string means "keep the repo default". AF_COLOR_TEXT=$(jq -r '.colors.COLOR_TEXT // ""' "$ANSWERFILE") AF_COLOR_BG=$(jq -r '.colors.COLOR_BG // ""' "$ANSWERFILE") @@ -484,6 +495,7 @@ printf "Dotfiles install: %s\nDotfiles dir: %s\n" "$(date)" "$DOTFILES_DIR" > # ── Welcome ─────────────────────────────────────────────────────────────────── if ! $ANSWERFILE_MODE; then + flush_tty_input ui_msgbox " Welcome " "\ the_miro's Arch dotfiles installer\n\ Cyberqueer · Wayland · Hyprland\n\ @@ -503,13 +515,17 @@ if $ANSWERFILE_MODE; then COMPONENTS="$AF_COMPONENTS" else # ui_checklist takes tag/desc/state triplets and echoes the selected tags. - # All four components are pre-selected ("on") because they form the expected base. + # All five components are pre-selected ("on") because they form the expected base. + # "shellrc" is split out from "shell" so the shell tools/plugins/programs can be + # installed without symlinking the personal .bashrc/.zshrc/.vimrc over them — + # it only has an effect when "shell" is also selected. # Entering 'q' returns exit code 1; the '|| { ...; exit 0; }' treats that as a clean abort. COMPONENTS=$(ui_checklist " Select Components " "Optional base components — all enabled by default:" \ "pkg" "pkg Package managers yay · nvm · rust" on \ "core" "core Core packages 100+ base system packages" on \ "svc" "svc Core services NetworkManager · cronie · fail2ban" on \ - "shell" "shell Shell setup zsh · nvim · yazi · micro · starship" on) \ + "shell" "shell Shell setup zsh · nvim · yazi · micro · starship" on \ + "shellrc" "shellrc Personal shell rc's .bashrc/.zshrc/.vimrc (needs shell)" on) \ || { clear; echo "Aborted."; exit 0; } fi @@ -624,13 +640,13 @@ else fi # ── Shell RC preference ─────────────────────────────────────────────────────── -if $ANSWERFILE_MODE; then - SHELL_RC="$AF_SHELL_RC" +# Derived from the "shellrc" component rather than asked separately: it only takes +# effect when "shell" also runs, and whether new users (via /etc/skel) inherit the +# rc files should follow the same choice as the current user's deployment. +if [[ " $COMPONENTS " == *" shell "* && " $COMPONENTS " == *" shellrc "* ]]; then + SHELL_RC="dotfiles" else - SHELL_RC=$(ui_menu " Shell Config for New Users " \ - "Should new users on this machine inherit the dotfiles' rc files?\n (Controls what gets copied to /etc/skel)" \ - "dotfiles" "Use the_miro's .zshrc / .bashrc / .vimrc from dotfiles" \ - "defaults" "Skip — use system defaults for new users") || SHELL_RC="defaults" + SHELL_RC="defaults" fi # ── Confirmation (interactive mode only) ────────────────────────────────────── @@ -638,13 +654,14 @@ if ! $ANSWERFILE_MODE; then # Build a human-readable summary of everything that will be installed so the # user can review the full list before any changes are made to the system. SUMMARY="" - [[ "$COMPONENTS" == *"pkg"* ]] && SUMMARY+=" ✦ Package managers (yay, nvm, rust)\n" - [[ "$COMPONENTS" == *"core"* ]] && SUMMARY+=" ✦ Core packages\n" - [[ "$COMPONENTS" == *"svc"* ]] && SUMMARY+=" ✦ Core services\n" - [[ "$COMPONENTS" == *"shell"* ]] && SUMMARY+=" ✦ Shell setup\n" + [[ " $COMPONENTS " == *" pkg "* ]] && SUMMARY+=" ✦ Package managers (yay, nvm, rust)\n" + [[ " $COMPONENTS " == *" core "* ]] && SUMMARY+=" ✦ Core packages\n" + [[ " $COMPONENTS " == *" svc "* ]] && SUMMARY+=" ✦ Core services\n" + [[ " $COMPONENTS " == *" shell "* ]] && SUMMARY+=" ✦ Shell setup (plugins & programs)\n" + [[ "$SHELL_RC" == "dotfiles" ]] && SUMMARY+=" ✦ Personal shell rc's (.bashrc/.zshrc/.vimrc)\n" [[ "$DE" != "none" && "$DE" != "" ]] && SUMMARY+=" ✦ Desktop environment: $DE\n" - [[ "$SHELL_RC" == "dotfiles" ]] && SUMMARY+=" ✦ Shell rc files → /etc/skel (dotfiles)\n" \ - || SUMMARY+=" ✦ Shell rc files → /etc/skel (system defaults)\n" + [[ "$SHELL_RC" == "dotfiles" ]] && SUMMARY+=" ✦ Shell rc's → /etc/skel for new users (dotfiles)\n" \ + || SUMMARY+=" ✦ Shell rc's → /etc/skel for new users (system defaults)\n" if [[ -n "$SELECTED_APPS" ]]; then SUMMARY+="\n Applications:\n" @@ -741,12 +758,16 @@ fi count_steps "$COMPONENTS" "$DE" "$SELECTED_APPS" # ── Installation: base components ───────────────────────────────────────────── -# Each guard uses glob matching against the space-separated COMPONENTS string. +# Each guard uses padded-space glob matching against the COMPONENTS string so +# "shell" doesn't false-match the "shellrc" tag. # Order matters: package managers must be installed before packages that need yay/rust. -[[ "$COMPONENTS" == *"pkg"* ]] && run_module "Package Managers" "$MODULES/package-managers.sh" -[[ "$COMPONENTS" == *"core"* ]] && run_module "Core Packages" "$MODULES/core-packages.sh" -[[ "$COMPONENTS" == *"svc"* ]] && run_module "Core Services" "$MODULES/core.sh" -[[ "$COMPONENTS" == *"shell"* ]] && run_module "Shell Setup" "$MODULES/shell-setup.sh" +[[ " $COMPONENTS " == *" pkg "* ]] && run_module "Package Managers" "$MODULES/package-managers.sh" +[[ " $COMPONENTS " == *" core "* ]] && run_module "Core Packages" "$MODULES/core-packages.sh" +[[ " $COMPONENTS " == *" svc "* ]] && run_module "Core Services" "$MODULES/core.sh" +# MARCHY_DEPLOY_SHELL_RC tells shell-setup.sh whether to symlink the personal +# .bashrc/.zshrc/.vimrc, independently of installing the shell tools/plugins themselves. +[[ " $COMPONENTS " == *" shellrc "* ]] && export MARCHY_DEPLOY_SHELL_RC=1 || export MARCHY_DEPLOY_SHELL_RC=0 +[[ " $COMPONENTS " == *" shell "* ]] && run_module "Shell Setup" "$MODULES/shell-setup.sh" # Route the single selected DE value to its corresponding install script. # "none" is the skip sentinel — no case branch matches it intentionally.