Files
StianNOR-ZSHkit/update_zshrc.sh
2026-03-25 15:22:34 +01:00

187 lines
6.0 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# =============================================================================
# 🔧 StianNOR-ZSHkit — .zshrc Merge Script
# Merges managed sections from ZSHkit/.zshrc into the live ~/.zshrc
# without overwriting personal aliases or custom configuration.
#
# How it works:
# - Managed sections in ~/.zshrc are wrapped with markers:
# # --- ZSHKIT:section_name ---
# ... content ...
# # --- /ZSHKIT:section_name ---
# - On first run, markers are injected into your existing ~/.zshrc
# - On subsequent runs, content between markers is updated from ZSHkit
# - Everything outside the markers is never touched
#
# Usage:
# ./update_zshrc.sh — merge and apply
# ./update_zshrc.sh --dry-run — show what would change, no writes
# ./update_zshrc.sh --status — show which sections are present
# =============================================================================
set -euo pipefail
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'
RED='\033[0;31m'; BOLD='\033[1m'; RESET='\033[0m'
LINE="────────────────────────────────────────────────────────────────────────────"
info() { echo -e "${CYAN} $*${RESET}"; }
success() { echo -e "${GREEN}$*${RESET}"; }
warn() { echo -e "${YELLOW}$*${RESET}"; }
error() { echo -e "${RED}$*${RESET}"; }
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SOURCE="$SCRIPT_DIR/.zshrc"
TARGET="$HOME/.zshrc"
BACKUP="$HOME/.zshrc.bak.$(date +%Y%m%d-%H%M%S)"
DRY_RUN=false
STATUS_ONLY=false
case "${1:-}" in
--dry-run) DRY_RUN=true ;;
--status) STATUS_ONLY=true ;;
esac
if [[ ! -f "$SOURCE" ]]; then
error "Source not found: $SOURCE"
exit 1
fi
if [[ ! -f "$TARGET" ]]; then
warn "No ~/.zshrc found — copying source directly"
cp "$SOURCE" "$TARGET"
success "Created $TARGET from ZSHkit source"
exit 0
fi
declare -A SECTION_START=(
[autosuggestions]="# ─── Autosuggestions"
[aliases]="# ─── User Aliases and Functions"
)
declare -A SECTION_END=(
[autosuggestions]="source \$ZSH/oh-my-zsh.sh"
[aliases]="alias rsy="
)
# =============================================================================
# STATUS MODE
# =============================================================================
if [[ "$STATUS_ONLY" = true ]]; then
echo -e "\n${BOLD}${CYAN}🔧 .zshrc Managed Sections Status${RESET}"
echo -e "${LINE}"
for section in "${!SECTION_START[@]}"; do
marker="# --- ZSHKIT:${section} ---"
if grep -qF "$marker" "$TARGET" 2>/dev/null; then
success "Section present: $section"
else
warn "Section missing (will be injected on next run): $section"
fi
done
echo -e "${LINE}\n"
exit 0
fi
# =============================================================================
# BACKUP
# =============================================================================
cp "$TARGET" "$BACKUP"
info "Backup saved: $BACKUP"
echo -e "\n${BOLD}${CYAN}🔧 Merging .zshrc sections${RESET}"
echo -e "${LINE}"
CHANGED=0
merge_section() {
local name="$1"
local start_pat="$2"
local end_pat="$3"
local begin_marker="# --- ZSHKIT:${name} ---"
local end_marker="# --- /ZSHKIT:${name} ---"
local new_content
new_content=$(awk "/$start_pat/{found=1} found{print} /$end_pat/{if(found) {found=0}}" "$SOURCE")
if [[ -z "$new_content" ]]; then
warn "Could not extract section '$name' from source — skipping"
return
fi
local block
block="$begin_marker
$new_content
$end_marker"
if grep -qF "$begin_marker" "$TARGET"; then
local existing
existing=$(awk "/$begin_marker/{found=1; next} /$end_marker/{found=0; next} found{print}" "$TARGET")
if [[ "$existing" == "$new_content" ]]; then
success "Up to date: $name"
return
fi
if [[ "$DRY_RUN" = true ]]; then
warn "[DRY RUN] Would update section: $name"
diff <(echo "$existing") <(echo "$new_content") || true
else
python3 - "$TARGET" "$begin_marker" "$end_marker" "$new_content" <<'PYEOF'
import sys, re
target = sys.argv[1]
begin = sys.argv[2]
end = sys.argv[3]
new_body = sys.argv[4]
with open(target, 'r') as f:
content = f.read()
pattern = re.escape(begin) + r'.*?' + re.escape(end)
replacement = begin + '\n' + new_body + '\n' + end
new_content = re.sub(pattern, replacement, content, flags=re.DOTALL)
with open(target, 'w') as f:
f.write(new_content)
PYEOF
success "Updated section: $name"
(( CHANGED++ )) || true
fi
else
if [[ "$DRY_RUN" = true ]]; then
warn "[DRY RUN] Would inject new section: $name"
else
if grep -q "# End of .zshrc" "$TARGET"; then
python3 - "$TARGET" "# End of .zshrc" "$block" <<'PYEOF'
import sys
target = sys.argv[1]
marker = sys.argv[2]
new_block = sys.argv[3]
with open(target, 'r') as f:
content = f.read()
content = content.replace(marker, new_block + '\n\n' + marker)
with open(target, 'w') as f:
f.write(content)
PYEOF
else
echo "" >> "$TARGET"
echo "$block" >> "$TARGET"
fi
success "Injected new section: $name"
(( CHANGED++ )) || true
fi
fi
}
merge_section "autosuggestions" \
"# ─── Autosuggestions" \
"source \\\$ZSH/oh-my-zsh.sh"
merge_section "aliases" \
"# ─── User Aliases and Functions" \
"alias rsy="
echo -e "${LINE}"
if [[ "$DRY_RUN" = true ]]; then
warn "Dry run complete — no files were modified"
elif [[ $CHANGED -eq 0 ]]; then
success "Everything already up to date — no changes needed"
else
success "$CHANGED section(s) updated in $TARGET"
echo -e "\n ${YELLOW}Run ${CYAN}fresh${RESET}${YELLOW} or open a new terminal to apply changes.${RESET}"
fi
echo -e "${LINE}\n"