Upload files to "/"

This commit is contained in:
2026-03-25 15:22:34 +01:00
parent 073c73dad8
commit d572d37aa7
5 changed files with 739 additions and 0 deletions

BIN
ZSH StianNOR install.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

459
uninstall.sh Normal file
View File

@@ -0,0 +1,459 @@
#!/bin/bash
# =============================================================================
# 🗑️ StianNOR — COMPLETE UNINSTALLER v1.0
# Uninstalls everything installed by:
# - setup_zsh_font.sh (Zsh, Oh My Zsh, p10k, plugins, colorls, fastfetch, Hack Nerd Font)
# - portainerup.sh (Portainer CE, Docker, Docker Compose)
# =============================================================================
set -uo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
BLUE='\033[0;34m'; CYAN='\033[0;36m'; 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}"; }
step() { echo -e "\n${BOLD}${BLUE}$*${RESET}"; echo -e "${BLUE}${LINE}${RESET}"; }
skip() { echo -e " ${BLUE}$* — not found, skipping${RESET}"; }
# =============================================================================
# DETECT PACKAGE MANAGER
# =============================================================================
detect_pm() {
if command -v pacman >/dev/null 2>&1; then PM="pacman"
elif command -v apt >/dev/null 2>&1; then PM="apt"
elif command -v dnf >/dev/null 2>&1; then PM="dnf"
elif command -v zypper >/dev/null 2>&1; then PM="zypper"
elif command -v apk >/dev/null 2>&1; then PM="apk"
else PM="unknown"; fi
}
detect_pm
pkg_remove() {
case "$PM" in
pacman) sudo pacman -Rns --noconfirm "$@" 2>/dev/null || true ;;
apt) sudo apt remove -y --purge "$@" 2>/dev/null || true; sudo apt autoremove -y 2>/dev/null || true ;;
dnf) sudo dnf remove -y "$@" 2>/dev/null || true ;;
zypper) sudo zypper remove -y "$@" 2>/dev/null || true ;;
apk) sudo apk del "$@" 2>/dev/null || true ;;
esac
}
# =============================================================================
# CONFIRM — show full plan before doing anything
# =============================================================================
clear
echo -e "${LINE}"
echo -e "${BOLD}${RED} 🗑️ StianNOR COMPLETE UNINSTALLER${RESET}"
echo -e "${LINE}"
echo ""
echo -e " This will remove the following — ${BOLD}select what to uninstall:${RESET}"
echo ""
echo -e " ${BOLD}${CYAN}[A] ZSH + FONT SETUP${RESET}"
echo -e " • Hack Nerd Font (system-wide)"
echo -e " • fontconfig monospace alias (/etc/fonts/local.conf)"
echo -e " • Oh My Zsh + Powerlevel10k + all plugins"
echo -e " • colorls Ruby gem"
echo -e " • fastfetch"
echo -e " • ~/.zshrc and ~/.p10k.zsh"
echo -e " • Default shell reverted to bash"
echo ""
echo -e " ${BOLD}${CYAN}[B] PORTAINER + DOCKER${RESET}"
echo -e " • Portainer CE container + data volume"
echo -e " • Docker CE + Docker Compose"
echo -e " • docker group membership for $USER"
echo -e " • Docker config dir (~/.docker)"
echo ""
echo -e " ${BOLD}${CYAN}[C] BOTH (full wipe)${RESET}"
echo ""
echo -e "${LINE}"
echo -e " ${YELLOW}[q]${RESET} cancel and exit"
echo -e "${LINE}"
echo ""
printf " Choice: "
read -r CHOICE
echo ""
case "${CHOICE,,}" in
a) DO_ZSH=true; DO_DOCKER=false ;;
b) DO_ZSH=false; DO_DOCKER=true ;;
c) DO_ZSH=true; DO_DOCKER=true ;;
q|"") echo -e " ${YELLOW}Cancelled.${RESET}"; exit 0 ;;
*) echo -e " ${RED}Invalid choice. Exiting.${RESET}"; exit 1 ;;
esac
# Final confirm
echo -e "${LINE}"
echo -e " ${BOLD}${RED}This is destructive and cannot be undone.${RESET}"
printf " Type ${BOLD}YES${RESET} to confirm: "
read -r CONFIRM
echo ""
[[ "$CONFIRM" != "YES" ]] && echo -e " ${YELLOW}Aborted.${RESET}" && exit 0
# =============================================================================
# LOG FILE
# =============================================================================
LOG_DIR="$HOME/Homelab/logs"
mkdir -p "$LOG_DIR" 2>/dev/null || LOG_DIR="/tmp"
LOG_FILE="$LOG_DIR/uninstall-$(date +%Y%m%d-%H%M%S).log"
exec > >(tee -a "$LOG_FILE") 2>&1
info "Logging to $LOG_FILE"
# =============================================================================
# A — UNINSTALL ZSH + FONT SETUP
# =============================================================================
uninstall_zsh_font() {
# ── 1. Revert default shell to bash ──────────────────────────────────────
step "Reverting default shell to bash"
BASH_PATH=$(command -v bash 2>/dev/null || echo "/bin/bash")
CURRENT_SHELL=$(getent passwd "$USER" | cut -d: -f7)
if [[ "$CURRENT_SHELL" == *zsh* ]]; then
grep -qxF "$BASH_PATH" /etc/shells || echo "$BASH_PATH" | sudo tee -a /etc/shells
if chsh -s "$BASH_PATH" 2>/dev/null; then
success "Default shell reverted to $BASH_PATH"
else
warn "Could not change shell automatically — run: chsh -s $BASH_PATH"
fi
else
skip "Shell was not zsh ($CURRENT_SHELL)"
fi
# ── 2. Remove Oh My Zsh ──────────────────────────────────────────────────
step "Removing Oh My Zsh"
if [[ -d "$HOME/.oh-my-zsh" ]]; then
rm -rf "$HOME/.oh-my-zsh"
success "Oh My Zsh removed"
else
skip "~/.oh-my-zsh"
fi
# ── 3. Remove Powerlevel10k (standalone clone, if outside OMZ) ───────────
step "Removing Powerlevel10k"
for p10k_path in \
"$HOME/.oh-my-zsh/custom/themes/powerlevel10k" \
"$HOME/powerlevel10k" \
"${ZSH_CUSTOM:-}/themes/powerlevel10k"; do
if [[ -d "$p10k_path" ]]; then
rm -rf "$p10k_path"
success "Removed $p10k_path"
fi
done
# ── 4. Remove Zsh plugin dirs ─────────────────────────────────────────────
step "Removing Zsh plugins"
for plugin in zsh-autosuggestions zsh-syntax-highlighting zsh-completions; do
PLUGIN_DIR="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/$plugin"
if [[ -d "$PLUGIN_DIR" ]]; then
rm -rf "$PLUGIN_DIR"
success "Removed plugin: $plugin"
else
skip "Plugin $plugin"
fi
done
# ── 5. Remove colorls gem ─────────────────────────────────────────────────
step "Removing colorls Ruby gem"
if gem list -i colorls >/dev/null 2>&1; then
gem uninstall colorls -a -x 2>/dev/null && success "colorls removed" \
|| warn "colorls uninstall had warnings"
else
skip "colorls gem"
fi
# Clean up gem home if empty
GEM_HOME_DIR="$HOME/.gem"
if [[ -d "$GEM_HOME_DIR" ]]; then
REMAINING=$(find "$GEM_HOME_DIR" -name "*.gemspec" 2>/dev/null | wc -l)
if [[ "$REMAINING" -eq 0 ]]; then
rm -rf "$GEM_HOME_DIR"
success "Removed empty ~/.gem"
else
info "$REMAINING other gems remain in ~/.gem — leaving it"
fi
fi
# ── 6. Remove fastfetch ───────────────────────────────────────────────────
step "Removing fastfetch"
if command -v fastfetch >/dev/null 2>&1; then
FF_PATH=$(command -v fastfetch)
# If installed via package manager
removed=false
case "$PM" in
pacman) sudo pacman -Rns --noconfirm fastfetch 2>/dev/null && removed=true ;;
apt) sudo apt remove -y --purge fastfetch 2>/dev/null && removed=true ;;
dnf) sudo dnf remove -y fastfetch 2>/dev/null && removed=true ;;
zypper) sudo zypper remove -y fastfetch 2>/dev/null && removed=true ;;
apk) sudo apk del fastfetch 2>/dev/null && removed=true ;;
esac
# If it was a manually installed binary
if [[ "$removed" == false ]] || command -v fastfetch >/dev/null 2>&1; then
sudo rm -f /usr/local/bin/fastfetch /usr/bin/fastfetch 2>/dev/null || true
fi
command -v fastfetch >/dev/null 2>&1 \
&& warn "fastfetch still found at $(command -v fastfetch) — remove manually" \
|| success "fastfetch removed"
else
skip "fastfetch"
fi
# ── 7. Remove Zsh itself ──────────────────────────────────────────────────
step "Removing Zsh"
if command -v zsh >/dev/null 2>&1; then
printf " Remove zsh package itself? (leaves system zsh on some distros) [y/N]: "
read -r yn
if [[ "${yn,,}" == "y" ]]; then
pkg_remove zsh
command -v zsh >/dev/null 2>&1 \
&& warn "zsh still present (may be a system dependency)" \
|| success "zsh removed"
else
info "Zsh package kept (shell reverted to bash above)"
fi
else
skip "zsh (not installed)"
fi
# ── 8. Remove dot files ───────────────────────────────────────────────────
step "Removing ~/.zshrc and ~/.p10k.zsh"
for f in "$HOME/.zshrc" "$HOME/.p10k.zsh" "$HOME/.zsh_history"; do
if [[ -f "$f" ]]; then
# Back up before deleting
cp "$f" "${f}.uninstall-backup-$(date +%Y%m%d)" 2>/dev/null || true
rm -f "$f"
success "Removed $f (backup saved as ${f}.uninstall-backup-*)"
else
skip "$f"
fi
done
# ── 9. Remove Hack Nerd Font ──────────────────────────────────────────────
step "Removing Hack Nerd Font"
FONT_DIR="/usr/local/share/fonts/nerd-fonts"
if [[ -d "$FONT_DIR" ]]; then
sudo rm -rf "$FONT_DIR"
sudo fc-cache -f 2>/dev/null || true
success "Hack Nerd Font removed from $FONT_DIR"
else
skip "$FONT_DIR"
fi
# Also check user font dir
USER_FONT_DIR="$HOME/.local/share/fonts/nerd-fonts"
if [[ -d "$USER_FONT_DIR" ]]; then
rm -rf "$USER_FONT_DIR"
fc-cache -f "$HOME/.local/share/fonts" 2>/dev/null || true
success "Removed user font dir $USER_FONT_DIR"
fi
# ── 10. Remove fontconfig override ───────────────────────────────────────
step "Removing fontconfig monospace alias"
if [[ -f /etc/fonts/local.conf ]]; then
if grep -q "Hack Nerd Font" /etc/fonts/local.conf 2>/dev/null; then
sudo rm -f /etc/fonts/local.conf
sudo fc-cache -f 2>/dev/null || true
success "Removed /etc/fonts/local.conf"
else
info "/etc/fonts/local.conf exists but doesn't contain Hack Nerd Font — leaving it"
fi
else
skip "/etc/fonts/local.conf"
fi
# ── 11. Clean up PATH entries added to shell rc files ────────────────────
step "Cleaning gem PATH entries from shell rc files"
for rc in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.bash_profile" "$HOME/.profile"; do
if [[ -f "$rc" ]]; then
if grep -q "\.gem" "$rc" 2>/dev/null; then
sed -i '/\.gem\/ruby/d' "$rc" 2>/dev/null || true
sed -i '/GEM_HOME/d' "$rc" 2>/dev/null || true
success "Cleaned gem PATH from $rc"
fi
fi
done
}
# =============================================================================
# B — UNINSTALL PORTAINER + DOCKER
# =============================================================================
uninstall_docker_portainer() {
# ── 1. Stop and remove Portainer ─────────────────────────────────────────
step "Removing Portainer CE"
if command -v docker >/dev/null 2>&1; then
DOCKER_CMD="docker"
docker info >/dev/null 2>&1 || DOCKER_CMD="sudo docker"
if $DOCKER_CMD ps -a --format '{{.Names}}' 2>/dev/null | grep -q "^portainer$"; then
$DOCKER_CMD stop portainer 2>/dev/null || true
$DOCKER_CMD rm portainer 2>/dev/null || true
success "Portainer container stopped and removed"
else
skip "Portainer container"
fi
# Remove portainer data volume
if $DOCKER_CMD volume ls --format '{{.Name}}' 2>/dev/null | grep -q "^portainer_data$"; then
printf " Remove portainer_data volume? This deletes all Portainer settings [y/N]: "
read -r yn
if [[ "${yn,,}" == "y" ]]; then
$DOCKER_CMD volume rm portainer_data 2>/dev/null || true
success "portainer_data volume removed"
else
info "portainer_data volume kept"
fi
else
skip "portainer_data volume"
fi
# Remove the image
if $DOCKER_CMD image ls --format '{{.Repository}}:{{.Tag}}' 2>/dev/null | grep -q "portainer/portainer-ce"; then
printf " Remove Portainer CE docker image? [y/N]: "
read -r yn
if [[ "${yn,,}" == "y" ]]; then
$DOCKER_CMD rmi portainer/portainer-ce:latest 2>/dev/null || true
success "Portainer CE image removed"
else
info "Portainer CE image kept"
fi
fi
else
skip "Docker not installed — Portainer check skipped"
fi
# ── 2. Remove Docker ──────────────────────────────────────────────────────
step "Removing Docker"
if command -v docker >/dev/null 2>&1; then
printf " ${BOLD}${RED}Remove Docker CE completely?${RESET} This removes ALL containers, images and volumes [y/N]: "
read -r yn
if [[ "${yn,,}" != "y" ]]; then
info "Docker kept — only Portainer was removed"
return
fi
# Stop daemon first
sudo systemctl stop docker docker.socket 2>/dev/null || sudo service docker stop 2>/dev/null || true
sudo systemctl disable docker docker.socket 2>/dev/null || true
case "$PM" in
pacman)
sudo pacman -Rns --noconfirm docker docker-compose 2>/dev/null || true
;;
apt)
sudo apt remove -y --purge \
docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin \
docker-compose 2>/dev/null || true
sudo apt autoremove -y 2>/dev/null || true
# Remove Docker apt repo
sudo rm -f /etc/apt/sources.list.d/docker.list
sudo rm -f /etc/apt/keyrings/docker.gpg
sudo apt update -qq 2>/dev/null || true
;;
dnf)
sudo dnf remove -y \
docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin 2>/dev/null || true
sudo rm -f /etc/yum.repos.d/docker-ce.repo 2>/dev/null || true
;;
zypper)
sudo zypper remove -y docker docker-compose 2>/dev/null || true
;;
apk)
sudo apk del docker docker-compose 2>/dev/null || true
sudo rc-update del docker boot 2>/dev/null || true
;;
esac
# Remove standalone docker-compose binary if present
[[ -f /usr/local/bin/docker-compose ]] && sudo rm -f /usr/local/bin/docker-compose \
&& success "Removed standalone docker-compose"
success "Docker CE removed"
else
skip "Docker (not installed)"
fi
# ── 3. Remove Docker data directories ────────────────────────────────────
step "Removing Docker data directories"
for dir in /var/lib/docker /var/lib/containerd /etc/docker; do
if [[ -d "$dir" ]]; then
printf " Remove %s? [y/N]: " "$dir"
read -r yn
if [[ "${yn,,}" == "y" ]]; then
sudo rm -rf "$dir"
success "Removed $dir"
else
info "Kept $dir"
fi
else
skip "$dir"
fi
done
# Remove user docker config
if [[ -d "$HOME/.docker" ]]; then
rm -rf "$HOME/.docker"
success "Removed ~/.docker"
fi
# ── 4. Remove user from docker group ─────────────────────────────────────
step "Removing $USER from docker group"
if getent group docker >/dev/null 2>&1; then
if groups "$USER" | grep -qw docker; then
sudo gpasswd -d "$USER" docker 2>/dev/null \
&& success "$USER removed from docker group" \
|| warn "Could not remove $USER from docker group"
else
skip "$USER was not in docker group"
fi
printf " Delete the docker group itself? [y/N]: "
read -r yn
if [[ "${yn,,}" == "y" ]]; then
sudo groupdel docker 2>/dev/null && success "docker group deleted" \
|| warn "Could not delete docker group"
fi
else
skip "docker group (does not exist)"
fi
# ── 5. Remove Docker socket and service files (if any remain) ────────────
step "Cleaning up Docker service files"
for f in \
/lib/systemd/system/docker.service \
/lib/systemd/system/docker.socket \
/etc/systemd/system/docker.service \
/etc/systemd/system/docker.socket; do
if [[ -f "$f" ]]; then
sudo rm -f "$f"
success "Removed $f"
fi
done
sudo systemctl daemon-reload 2>/dev/null || true
}
# =============================================================================
# RUN SELECTED SECTIONS
# =============================================================================
[[ "$DO_ZSH" == true ]] && uninstall_zsh_font
[[ "$DO_DOCKER" == true ]] && uninstall_docker_portainer
# =============================================================================
# DONE
# =============================================================================
echo ""
echo -e "${LINE}"
echo -e "${BOLD}${GREEN} ✅ Uninstall complete!${RESET}"
echo -e "${LINE}"
[[ "$DO_ZSH" == true ]] && echo -e " ${CYAN}Zsh/Font:${RESET} removed — default shell reverted to bash"
[[ "$DO_DOCKER" == true ]] && echo -e " ${CYAN}Docker:${RESET} removed — log out and back in to clear group session"
echo -e " ${YELLOW}Log:${RESET} $LOG_FILE"
echo -e "${LINE}"
echo ""
if [[ "$DO_ZSH" == true ]]; then
echo -e " ${YELLOW}Note:${RESET} Log out and back in for shell change to take full effect."
fi
if [[ "$DO_DOCKER" == true ]]; then
echo -e " ${YELLOW}Note:${RESET} Log out and back in to clear docker group from your session."
fi
echo ""

94
uninstall_zsh_setup.sh Normal file
View File

@@ -0,0 +1,94 @@
#!/bin/bash
set -e # Exit immediately if a command exits with a non-zero status
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BOLD='\033[1m'
NC='\033[0m' # No Color
info() { echo -e "${YELLOW} $*${NC}"; }
success() { echo -e "${GREEN}$*${NC}"; }
warn() { echo -e "${YELLOW}⚠️ $*${NC}"; }
error() { echo -e "${RED}$*${NC}"; }
step() { echo -e "${BOLD}${YELLOW}--- $* ---${NC}"; }
step "Uninstalling Zsh/Powerlevel10k setup and related tools"
# 1. Remove Oh My Zsh directory
info "Removing Oh My Zsh directory..."
if [ -d "$HOME/.oh-my-zsh" ]; then
rm -rf "$HOME/.oh-my-zsh"
success "Oh My Zsh directory removed."
else
warn "Oh My Zsh directory not found."
fi
# 2. Remove Zsh configuration files
info "Removing Zsh configuration files..."
ZSH_CONFIG_FILES=("$HOME/.zshrc" "$HOME/.zshenv" "$HOME/.zprofile" "$HOME/.zlogin" "$HOME/.p10k.zsh")
for file in "${ZSH_CONFIG_FILES[@]}"; do
if [ -f "$file" ]; then
rm -f "$file"
success "Removed $file"
else
warn "$file not found."
fi
done
# 3. Remove up.sh maintenance script
info "Removing up.sh maintenance script..."
if [ -f "$HOME/Documents/up.sh" ]; then
rm -f "$HOME/Documents/up.sh"
success "up.sh maintenance script removed."
else
warn "up.sh maintenance script not found."
fi
# 4. Uninstall colorls (user gem)
info "Uninstalling colorls Ruby gem..."
# Ensure GEM_HOME and PATH are set correctly for user gems
export GEM_HOME="$HOME/.gem"
export PATH="$PATH:$GEM_HOME/bin"
if gem list -i colorls >/dev/null 2>&1; then
if gem uninstall colorls; then # Removed -x and sudo
success "colorls uninstalled."
else
error "Failed to uninstall colorls."
fi
else
warn "colorls gem not found."
fi
# 5. Uninstall fastfetch
info "Uninstalling fastfetch..."
if command -v fastfetch >/dev/null 2>&1; then
# Assume it was installed via the curl installer which puts files in /usr/local
if sudo rm -f /usr/local/bin/fastfetch && sudo rm -rf /usr/local/share/fastfetch; then
success "fastfetch uninstalled."
else
error "Failed to remove fastfetch binaries. Manual removal may be needed."
fi
else
warn "fastfetch not found."
fi
# 6. Optionally restore default shell to bash
# Check if zsh is the current default shell before attempting to change
CURRENT_DEFAULT_SHELL=$(getent passwd "$USER" | awk -F: '{print $NF}')
if [ "$CURRENT_DEFAULT_SHELL" != "/bin/bash" ] && [ -f "/bin/bash" ]; then
info "Restoring default shell to /bin/bash..."
if chsh -s /bin/bash "$USER"; then # Specify user for chsh
success "Default shell changed to /bin/bash."
echo -e "${GREEN}Please log out and log in again for shell changes to take effect.${NC}"
else
error "Failed to change default shell to /bin/bash. You may need to do it manually."
fi
else
success "Default shell is already /bin/bash or /bin/bash not found."
fi
echo -e "${BOLD}${GREEN}✅ Uninstallation complete.${NC}"
echo -e "${BOLD}${GREEN}Note: Log out and log back in for shell changes to fully apply.${NC}"

BIN
up.sh Normal file

Binary file not shown.

186
update_zshrc.sh Normal file
View File

@@ -0,0 +1,186 @@
#!/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"