This commit is contained in:
2025-08-09 09:33:42 +01:00
parent 1f239236b3
commit aebb4a9601

View File

@@ -1,18 +1,23 @@
#!/bin/bash #!/bin/bash
set -euo pipefail set -euo pipefail
# ====================== Defaults & Args ====================== # ====================== Flags ======================
WITH_TIDE=0 WITH_TIDE=0
KEEP_PROMPT=0 KEEP_PROMPT=0
REMOVE_TIDE=0
VERBOSE=0 VERBOSE=0
NO_PLUGINS=0 NO_PLUGINS=0
UPDATE_MODE="prompt" # prompt | yes | no
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
--with-tide) WITH_TIDE=1 ;; --with-tide) WITH_TIDE=1 ;;
--keep-prompt) KEEP_PROMPT=1 ;; --keep-prompt) KEEP_PROMPT=1 ;;
--remove-tide) REMOVE_TIDE=1 ;;
--verbose) VERBOSE=1 ;; --verbose) VERBOSE=1 ;;
--no-plugins) NO_PLUGINS=1 ;; --no-plugins) NO_PLUGINS=1 ;;
--update-check) UPDATE_MODE="yes" ;;
--no-update-check) UPDATE_MODE="no" ;;
--) shift; break ;; --) shift; break ;;
*) echo "Unknown option: $1"; exit 1 ;; *) echo "Unknown option: $1"; exit 1 ;;
esac esac
@@ -21,18 +26,17 @@ done
# Default plugin set (safe; no prompt change) # Default plugin set (safe; no prompt change)
PLUGINS=("jethrokuan/z" "jorgebucaran/nvm.fish") PLUGINS=("jethrokuan/z" "jorgebucaran/nvm.fish")
if [[ $WITH_TIDE -eq 1 ]]; then [[ $WITH_TIDE -eq 1 ]] && PLUGINS+=("ilancosman/tide")
PLUGINS+=("ilancosman/tide")
fi
# ====================== UI Helpers ======================
log() { echo -e "$*"; } log() { echo -e "$*"; }
ok() { echo -e "$*"; } ok() { echo -e "$*"; }
warn(){ echo -e "! $*" >&2; } warn(){ echo -e "! $*" >&2; }
# ====================== Progress Bar (single line) ======================
padright() { printf "%-28s" "$1"; } padright() { printf "%-28s" "$1"; }
draw_bar() { draw_bar() {
local cur="$1" total="$2" label="$3" width=40 local cur="$1" total="$2" label="$3" width=40
(( total == 0 )) && total=1
local percent=$(( cur * 100 / total )) local percent=$(( cur * 100 / total ))
(( percent > 100 )) && percent=100 (( percent > 100 )) && percent=100
local filled=$(( width * cur / total )) local filled=$(( width * cur / total ))
@@ -45,6 +49,17 @@ draw_bar() {
"$percent" "$percent"
} }
prompt_yn_tty() {
local prompt="${1:-Proceed (y/N): }"
local d="${2:-N}" ans=""
if [ -r /dev/tty ] && [ -w /dev/tty ]; then
read -r -p "$prompt" ans </dev/tty || true
[[ ${ans:-$d} =~ ^[Yy]$ ]]
else
[[ "$d" =~ ^[Yy]$ ]]
fi
}
# ====================== Platform Detect ====================== # ====================== Platform Detect ======================
detect_platform() { detect_platform() {
if [[ "$OSTYPE" == "darwin"* ]]; then if [[ "$OSTYPE" == "darwin"* ]]; then
@@ -93,49 +108,98 @@ install_fish() {
esac esac
ok "Fish installed" ok "Fish installed"
} }
should_check_updates() {
case "$UPDATE_MODE" in
yes) return 0 ;;
no) return 1 ;;
prompt)
prompt_yn_tty "Check for Fish updates (may run a repo refresh)? (y/N): " "N"
return $? ;;
esac
}
update_fish_if_available() { update_fish_if_available() {
log "Checking Fish updates…" log "Checking Fish updates…"
case "$PKG_MGR" in case "$PKG_MGR" in
apt) sudo apt update; apt list --upgradable 2>/dev/null | grep -q "^fish/" && sudo apt install -y fish || true ;; apt)
dnf|yum) sudo "$PKG_MGR" check-update || true; "$PKG_MGR" list updates | grep -q "^fish" && sudo "$PKG_MGR" update -y fish || true ;; if should_check_updates; then
pacman) sudo pacman -Sy --noconfirm; pacman -Qu | grep -q "^fish" && sudo pacman -S --noconfirm fish || true ;; sudo apt update
brew) brew update; brew outdated | grep -q "^fish" && brew upgrade fish || true ;; apt list --upgradable 2>/dev/null | grep -q "^fish/" && sudo apt install -y fish || true
else
ok "Skipped update check"
fi
;;
dnf|yum)
if should_check_updates; then
sudo "$PKG_MGR" check-update || true
"$PKG_MGR" list updates | grep -q "^fish" && sudo "$PKG_MGR" update -y fish || true
else
ok "Skipped update check"
fi
;;
pacman)
if should_check_updates; then
sudo pacman -Sy --noconfirm
pacman -Qu | grep -q "^fish" && sudo pacman -S --noconfirm fish || true
else
ok "Skipped update check"
fi
;;
brew)
if should_check_updates; then
brew update
brew outdated | grep -q "^fish" && brew upgrade fish || true
else
ok "Skipped update check"
fi
;;
esac esac
ok "Fish up to date" ok "Fish up to date"
} }
# ====================== Fisher & Plugins ====================== # ====================== Fisher & Plugins ======================
ensure_fisher() { ensure_fisher() {
# install Fisher quietly and idempotently
if fish -c 'functions -q fisher' </dev/null >/dev/null 2>&1; then if fish -c 'functions -q fisher' </dev/null >/dev/null 2>&1; then
ok "Fisher already present" ok "Fisher already present"
return else
fi
log "Installing Fisher…" log "Installing Fisher…"
fish -c 'curl -sL https://git.io/fisher | source && fisher install jorgebucaran/fisher' </dev/null >/dev/null 2>&1 fish -c 'curl -sL https://git.io/fisher | source && fisher install jorgebucaran/fisher' </dev/null >/dev/null 2>&1
ok "Fisher installed" ok "Fisher installed"
fi
} }
install_plugins() { install_plugins() {
[[ $NO_PLUGINS -eq 1 ]] && { ok "Skipping plugins (per flag)"; return; } [[ $NO_PLUGINS -eq 1 ]] && { ok "Skipping plugins (per flag)"; return; }
local total=${#PLUGINS[@]} # Current installed plugins
[[ $total -eq 0 ]] && { ok "No plugins requested"; return; } local installed
installed="$(fish -c 'fisher list' </dev/null 2>/dev/null || true)"
if [[ $VERBOSE -eq 1 ]]; then # Determine missing plugins
local missing=()
for p in "${PLUGINS[@]}"; do for p in "${PLUGINS[@]}"; do
if ! grep -Fxq "$p" <<<"$installed"; then
missing+=("$p")
fi
done
# Nothing to do?
if [[ ${#missing[@]} -eq 0 ]]; then
ok "All requested plugins already installed"
else
if [[ $VERBOSE -eq 1 ]]; then
for p in "${missing[@]}"; do
echo "Installing (verbose): $p" echo "Installing (verbose): $p"
fish -c "fisher install $p" </dev/null fish -c "fisher install $p" </dev/null
done done
ok "Plugins installed" ok "Plugins installed"
return else
fi local total=${#missing[@]}
local i=0 local i=0
for p in "${PLUGINS[@]}"; do for p in "${missing[@]}"; do
i=$((i+1)) i=$((i+1))
draw_bar "$((i-1))" "$total" "$p" draw_bar "$((i-1))" "$total" "$p"
# run install in background and animate until it exits
( fish -c "fisher install $p" </dev/null >/dev/null 2>&1 ) & ( fish -c "fisher install $p" </dev/null >/dev/null 2>&1 ) &
pid=$! pid=$!
while kill -0 "$pid" 2>/dev/null; do while kill -0 "$pid" 2>/dev/null; do
@@ -146,6 +210,8 @@ install_plugins() {
done done
echo echo
ok "Plugins installed" ok "Plugins installed"
fi
fi
# If Tide installed but user wants to keep default prompt # If Tide installed but user wants to keep default prompt
if [[ $WITH_TIDE -eq 1 && $KEEP_PROMPT -eq 1 ]]; then if [[ $WITH_TIDE -eq 1 && $KEEP_PROMPT -eq 1 ]]; then
@@ -156,15 +222,40 @@ install_plugins() {
fi fi
} }
remove_tide_if_requested() {
[[ $REMOVE_TIDE -eq 0 ]] && return
ensure_fisher # make sure fisher exists so removal works
# Only remove if installed
if fish -c 'fisher list' </dev/null 2>/dev/null | grep -Fxq "ilancosman/tide"; then
log "Removing Tide…"
if [[ $VERBOSE -eq 1 ]]; then
fish -c "fisher remove ilancosman/tide" </dev/null
else
fish -c "fisher remove ilancosman/tide" </dev/null >/dev/null 2>&1
fi
fi
# Clean any prompt overrides
rm -f ~/.config/fish/functions/fish_prompt.fish \
~/.config/fish/conf.d/_tide_init.fish 2>/dev/null || true
ok "Tide removed and default prompt restored"
}
# ====================== Main ====================== # ====================== Main ======================
detect_platform detect_platform
install_gpg_if_needed
if command -v fish &>/dev/null; then if command -v fish &>/dev/null; then
ok "Fish already installed" ok "Fish already installed"
update_fish_if_available update_fish_if_available
else else
install_gpg_if_needed
install_fish install_fish
fi fi
ensure_fisher ensure_fisher
install_plugins install_plugins
remove_tide_if_requested
ok "Fish + Fisher + plugins ready on ${OS}" ok "Fish + Fisher + plugins ready on ${OS}"