From 073c73dad86618fcc1fb858fd4a030a79dcd8776 Mon Sep 17 00:00:00 2001 From: StianNOR Date: Wed, 25 Mar 2026 15:19:54 +0100 Subject: [PATCH] Upload files to "/" --- README.md | 160 +++++++++++++ Standard Terminal.png | Bin 0 -> 11770 bytes setup_zsh.sh | 507 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 667 insertions(+) create mode 100644 README.md create mode 100644 Standard Terminal.png create mode 100644 setup_zsh.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..4b0134e --- /dev/null +++ b/README.md @@ -0,0 +1,160 @@ +# StianNOR-ZSHkit 🚀 + +> A clean, powerful Zsh setup for Linux — featuring Powerlevel10k, Oh My Zsh, Hack Nerd Font, colorls, fastfetch, and a full-featured update dashboard with health checks, tool suggestions and interactive install mode. + +> [!TIP] +> Having issues? Please open an issue: [https://github.com/StianNOR/StianNOR-ZSHkit/issues](https://github.com/StianNOR/StianNOR-ZSHkit/issues) +> Join the community on Discord: [https://discord.gg/eHEHCzGCAE](https://discord.gg/eHEHCzGCAE) + +--- + +## What's Included + +- **Zsh** with Oh My Zsh and Powerlevel10k prompt +- **Hack Nerd Font** installed system-wide with automatic terminal/DE configuration +- **colorls** for beautiful directory listings +- **fastfetch** for a system info splash on terminal open +- **zsh-autosuggestions**, **zsh-syntax-highlighting**, **zsh-completions** plugins +- **Update Dashboard** (`up.sh`) — a full system update + health check tool with interactive tool browser +- **ZSHrc Merge Script** (`update_zshrc.sh`) — safely merges new features into your existing `~/.zshrc` without overwriting personal config + +--- + +## Supported Package Managers ✅ + +| Package Manager | Distros | +|-----------------|-------------------------------------------| +| **APT** | Debian, Ubuntu, Linux Mint, Pop!_OS, etc | +| **DNF** | Fedora, CentOS 8+, RHEL 8+, Rocky Linux, etc | +| **Pacman** | Arch Linux, Manjaro, EndeavourOS, etc | +| **Zypper** | openSUSE, SUSE Linux Enterprise, etc | +| **APK** | Alpine Linux | + +--- + +## Installation + +```bash +cd ~ +git clone https://github.com/StianNOR/StianNOR-ZSHkit.git ZSHkit +cd ZSHkit +chmod +x *.sh +./setup_zsh.sh +``` + +After installation, **log out and back in** (or reboot) for the shell change and font to take effect. + +Then run `p10k configure` to set up your prompt style. + +--- + +## Update Dashboard 🚀 + +The update dashboard keeps your system up to date and healthy with a single command. + +```bash +up # update everything: packages, flatpak, gems, Oh My Zsh, docker +upc # first-run config: full update + interactive tool install/suppress mode +uph # health check only +ups # tool suggestions and interactive info browser +uphelp # show all commands +``` + +### What `up` does + +- Updates system packages (pacman/yay, apt, dnf, zypper, or apk) +- Updates Flatpak apps +- Updates Ruby gems (colorls etc.) +- Updates Oh My Zsh and all custom plugins +- Prunes Docker images and volumes +- Cleans journals, thumbnail cache and /tmp +- Rotates logs automatically (keeps last 10) +- Shows a health summary with GOOD/BAD verdict + +### Tool Suggestions & Info Mode 📖 + +After running `upc` (or pressing `i` after `ups`), an interactive tool browser opens: + +| Category | Tools | +|----------|-------| +| 🔒 Security | UFW, fail2ban, rkhunter, lynis, ClamAV, auditd, AppArmor | +| ⚡ Optimization | earlyoom, irqbalance, thermald, zram, preload | +| 📡 Monitoring | btop, smartmontools, ncdu, gdu, duf, nethogs, logwatch, nvtop | +| 🛠 Terminal | bat, fzf, rsync, restic, tldr | +| 🌐 Network & Extras | nmap, mtr, timeshift, yay (Arch), nala (Debian) | + +**Controls:** + +| Key | Action | +|-----|--------| +| `↑` / `↓` | Navigate tools | +| `→` / `←` | Next / previous page | +| `i` | Queue tool for install | +| `s` | Suppress tool (hide from suggestions permanently) | +| `q` | Save and exit | + +--- + +## Keeping Your Config Up To Date + +If you already have a customised `~/.zshrc` and don't want it overwritten, use the merge script instead of copying: + +```bash +cd ~/ZSHkit +git pull +zup # merges new ZSHkit sections into your existing ~/.zshrc +fresh # reload +``` + +The merge script only updates the **managed sections** (aliases, autosuggestions config) and leaves everything else untouched. + +```bash +zup --dry-run # preview changes without writing anything +zup --status # check which sections are present in your ~/.zshrc +``` + +--- + +## Helpful Aliases + +| Alias | Description | +|-------|-------------| +| `up` | Run system updates | +| `upc` | First-run config + tool browser | +| `uph` | Health check | +| `ups` | Suggestions + info mode | +| `uphelp` | Show all up commands | +| `zup` | Merge new ZSHkit config into local ~/.zshrc | +| `fresh` | Reload ~/.zshrc | +| `ali` | Show all active aliases | +| `rsy` | rsync with progress display | +| `p10` | Launch Powerlevel10k configurator | +| `ls` / `ll` / `la` / `sls` | colorls variants | + +--- + +## Uninstall + +```bash +./uninstall_zsh_setup.sh +``` + +--- + +## Screenshots + +| Before | After | +| :---: | :---: | +| ![Before]() | ![After]() | + +--- + +## Author + +**StianNOR** + +--- + +## Disclaimer ⚠️ + +Provided *as-is* for supported Linux distributions. Always back up important data before running scripts. The author accepts no responsibility for data loss or damage. Test in a VM if unsure. diff --git a/Standard Terminal.png b/Standard Terminal.png new file mode 100644 index 0000000000000000000000000000000000000000..b2c96342d606c3b488d9a9632c9279cdbcd0bb6e GIT binary patch literal 11770 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 literal 0 HcmV?d00001 diff --git a/setup_zsh.sh b/setup_zsh.sh new file mode 100644 index 0000000..88c77a5 --- /dev/null +++ b/setup_zsh.sh @@ -0,0 +1,507 @@ +#!/bin/bash +# ============================================================================= +# 🚀 StianNOR — ZSH + NERD FONT SETUP v2.0 +# Merges font_nerd_hack.sh + setup_zsh.sh +# Supports: Arch/Manjaro, Debian/Ubuntu, Fedora, openSUSE, Alpine +# ============================================================================= +set -euo pipefail + +# --- Colors --- +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}"; } +die() { error "$*"; exit 1; } + +# --- Error trap --- +trap 'error "Failed at line $LINENO — command: $BASH_COMMAND"; exit 1' ERR + +# ============================================================================= +# 1. DETECT PACKAGE MANAGER +# ============================================================================= +step "Detecting 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 die "No supported package manager found."; fi + success "Package manager: $PM" +} +detect_pm + +pkg_install() { + case "$PM" in + pacman) sudo pacman -S --noconfirm --needed "$@" ;; + apt) sudo apt install -y "$@" ;; + dnf) sudo dnf install -y "$@" ;; + zypper) sudo zypper install -y "$@" ;; + apk) sudo apk add "$@" ;; + esac +} + +pkg_update() { + case "$PM" in + pacman) sudo pacman -Syu --noconfirm ;; + apt) sudo apt update ;; + dnf) sudo dnf check-update || true ;; + zypper) sudo zypper refresh ;; + apk) sudo apk update ;; + esac +} + +# ============================================================================= +# 2. DETECT ENVIRONMENT +# ============================================================================= +step "Detecting desktop environment and terminals" + +get_distro() { + [[ -f /etc/os-release ]] && { source /etc/os-release; echo "$NAME"; return; } + uname -s +} + +get_desktop() { + local de="${XDG_CURRENT_DESKTOP,,}" + [[ -z "$de" ]] && de="${DESKTOP_SESSION,,}" + echo "$de" +} + +get_terminals() { + local terms=() + for t in gnome-terminal konsole alacritty kitty wezterm xfce4-terminal mate-terminal tilix; do + pgrep -x "$t" >/dev/null 2>&1 && terms+=("$t") + done + # Also check $TERM_PROGRAM + [[ -n "${TERM_PROGRAM:-}" ]] && terms+=("${TERM_PROGRAM,,}") + # Deduplicate + printf '%s\n' "${terms[@]}" | sort -u | tr '\n' ' ' +} + +DISTRO_NAME=$(get_distro) +DESKTOP_ENV=$(get_desktop) +TERMINALS=$(get_terminals) + +info "Distro: $DISTRO_NAME" +info "Desktop: ${DESKTOP_ENV:-unknown}" +info "Terminals: ${TERMINALS:-none detected}" + +# ============================================================================= +# 3. INSTALL DEPENDENCIES +# ============================================================================= +step "Installing core dependencies" +pkg_update + +case "$PM" in + pacman) pkg_install curl git wget unzip ruby gcc make ;; + apt) sudo apt install -y curl git wget unzip ruby ruby-dev gcc make build-essential ;; + dnf) sudo dnf install -y curl git wget unzip ruby ruby-devel gcc make ;; + zypper) sudo zypper install -y curl git wget unzip ruby ruby-devel gcc make ;; + apk) sudo apk add curl git wget unzip ruby ruby-dev gcc make ;; +esac +success "Core dependencies installed" + +# ============================================================================= +# 4. INSTALL HACK NERD FONT +# ============================================================================= +step "Installing Hack Nerd Font" + +FONT_DIR="/usr/local/share/fonts/nerd-fonts" +FONT_ALIAS="Hack Nerd Font" +FONT_TMPDIR=$(mktemp -d) +FONT_VERSION="v3.4.0" + +# Ensure fontconfig tools available +command -v fc-cache >/dev/null 2>&1 || pkg_install fontconfig + +cleanup_font_tmp() { rm -rf "$FONT_TMPDIR"; } +trap 'cleanup_font_tmp; error "Failed at line $LINENO — command: $BASH_COMMAND"; exit 1' ERR +trap 'cleanup_font_tmp' EXIT + +info "Downloading Hack Nerd Font $FONT_VERSION..." +FONT_URL="https://github.com/ryanoasis/nerd-fonts/releases/download/${FONT_VERSION}/Hack.zip" +if command -v curl >/dev/null 2>&1; then + curl -fsSL "$FONT_URL" -o "$FONT_TMPDIR/Hack.zip" || die "Font download failed" +else + wget -q "$FONT_URL" -O "$FONT_TMPDIR/Hack.zip" || die "Font download failed" +fi + +info "Extracting fonts..." +unzip -q "$FONT_TMPDIR/Hack.zip" -d "$FONT_TMPDIR/Hack" || die "Font extraction failed" + +sudo mkdir -p "$FONT_DIR" +# Only copy TTF/OTF — skip Windows-compat and licence files +find "$FONT_TMPDIR/Hack" -name "*.ttf" -o -name "*.otf" | while read -r f; do + [[ "$f" =~ (Windows|LICENSE|README) ]] && continue + sudo cp "$f" "$FONT_DIR/" +done + +sudo fc-cache -f "$FONT_DIR" +success "Hack Nerd Font installed to $FONT_DIR" + +# --- Apply to Desktop Environment --- +FONT_GENERAL="$FONT_ALIAS 12" +FONT_MONO="$FONT_ALIAS 11" +FONT_SMALL="$FONT_ALIAS 8" +FONT_OTHER="$FONT_ALIAS 10" + +apply_kde_fonts() { + local kwrite + if command -v kwriteconfig6 >/dev/null 2>&1; then kwrite="kwriteconfig6" + elif command -v kwriteconfig5 >/dev/null 2>&1; then kwrite="kwriteconfig5" + else warn "kwriteconfig not found — KDE font config skipped"; return; fi + + $kwrite --file kdeglobals --group General --key font "$FONT_ALIAS,12,-1,5,50,0,0,0,0,0" + $kwrite --file kdeglobals --group Fixed --key font "$FONT_ALIAS,11,-1,5,50,0,0,0,0,0" + $kwrite --file kdeglobals --group Small --key font "$FONT_ALIAS,8,-1,5,50,0,0,0,0,0" + $kwrite --file kdeglobals --group Toolbar --key font "$FONT_ALIAS,10,-1,5,50,0,0,0,0,0" + $kwrite --file kdeglobals --group Menu --key font "$FONT_ALIAS,10,-1,5,50,0,0,0,0,0" + $kwrite --file kdeglobals --group "Window Title" --key font "$FONT_ALIAS,10,-1,5,50,0,0,0,0,0" + $kwrite --file kdeglobals --group General --key antialiasing "true" + $kwrite --file kdeglobals --group General --key hinting "slight" + $kwrite --file kdeglobals --group General --key subpixelRendering "rgb" + $kwrite --file kdeglobals --group General --key forceFontDpi 96 + # Konsole profiles + find ~/.local/share/konsole -name "*.profile" 2>/dev/null \ + -exec sed -i "s/^Font=.*/Font=$FONT_ALIAS,12,-1,5,50,0,0,0,0,0,Regular/" {} \; + success "KDE fonts applied via $kwrite" +} + +apply_gnome_fonts() { + command -v gsettings >/dev/null 2>&1 || { warn "gsettings not found — GNOME font config skipped"; return; } + gsettings set org.gnome.desktop.interface font-name "$FONT_GENERAL" + gsettings set org.gnome.desktop.interface monospace-font-name "$FONT_MONO" + gsettings set org.gnome.desktop.interface document-font-name "$FONT_GENERAL" + # GNOME Terminal profiles via dconf + if command -v dconf >/dev/null 2>&1; then + while IFS= read -r profile; do + [[ -z "$profile" ]] && continue + dconf write "/org/gnome/terminal/legacy/profiles:/:${profile}/use-system-font" "false" + dconf write "/org/gnome/terminal/legacy/profiles:/:${profile}/font" "'$FONT_MONO'" + done < <(dconf list /org/gnome/terminal/legacy/profiles:/ 2>/dev/null | grep -oP '[^/:]+' || true) + fi + success "GNOME/Cinnamon fonts applied" +} + +apply_xfce_fonts() { + command -v xfconf-query >/dev/null 2>&1 || { warn "xfconf-query not found — XFCE font config skipped"; return; } + xfconf-query -c xsettings -p /Gtk/FontName -s "$FONT_GENERAL" 2>/dev/null || true + xfconf-query -c xfwm4 -p /general/font -s "$FONT_GENERAL" 2>/dev/null || true + local xterm_conf="$HOME/.config/xfce4/terminal/terminalrc" + if [[ -f "$xterm_conf" ]]; then + sed -i "s/^FontName=.*/FontName=$FONT_MONO/" "$xterm_conf" + fi + success "XFCE fonts applied" +} + +apply_mate_fonts() { + command -v gsettings >/dev/null 2>&1 || { warn "gsettings not found — MATE font config skipped"; return; } + gsettings set org.mate.interface font-name "$FONT_GENERAL" 2>/dev/null || true + success "MATE fonts applied" +} + +case "$DESKTOP_ENV" in + *kde*|*plasma*) apply_kde_fonts ;; + *gnome*|*cinnamon*|*unity*) apply_gnome_fonts ;; + *xfce*) apply_xfce_fonts ;; + *mate*) apply_mate_fonts ;; + *) warn "Desktop '$DESKTOP_ENV' not specifically handled — font installed system-wide via fontconfig" ;; +esac + +# --- Apply to detected terminal emulators --- +apply_terminal_font() { + local term="$1" + case "$term" in + alacritty) + # Support both .yml (old) and .toml (new Alacritty >=0.13) + local conf_toml="$HOME/.config/alacritty/alacritty.toml" + local conf_yml="$HOME/.config/alacritty/alacritty.yml" + if [[ -f "$conf_toml" ]]; then + if grep -q '^\[font\]' "$conf_toml"; then + sed -i '/^\[font\]/,/^\[/{s/^family = .*/family = "'"$FONT_ALIAS"'"/}' "$conf_toml" + else + printf '\n[font]\n[font.normal]\nfamily = "%s"\n[font.bold]\nfamily = "%s"\n[font.italic]\nfamily = "%s"\n\n[font.size]\nsize = 12.0\n' \ + "$FONT_ALIAS" "$FONT_ALIAS" "$FONT_ALIAS" >> "$conf_toml" + fi + success "Alacritty TOML font updated" + elif [[ -f "$conf_yml" ]]; then + sed -i "/^ *family:/c\\ family: \"$FONT_ALIAS\"" "$conf_yml" + sed -i "/^ *size:/c\\ size: 12" "$conf_yml" + success "Alacritty YAML font updated" + else + warn "Alacritty config not found at $conf_toml or $conf_yml — skipping" + fi + ;; + kitty) + local kconf="$HOME/.config/kitty/kitty.conf" + mkdir -p "$(dirname "$kconf")" + if [[ -f "$kconf" ]]; then + sed -i "/^font_family/c\\font_family $FONT_ALIAS" "$kconf" + sed -i "/^font_size/c\\font_size 12.0" "$kconf" + else + printf 'font_family %s\nfont_size 12.0\n' "$FONT_ALIAS" > "$kconf" + fi + success "Kitty font configured" + ;; + wezterm) + local wconf="$HOME/.config/wezterm/wezterm.lua" + if [[ -f "$wconf" ]]; then + warn "WezTerm config found at $wconf — add this manually:" + echo " config.font = wezterm.font('$FONT_ALIAS')" + fi + ;; + konsole) + find ~/.local/share/konsole -name "*.profile" 2>/dev/null \ + -exec sed -i "s/^Font=.*/Font=$FONT_ALIAS,12,-1,5,50,0,0,0,0,0,Regular/" {} \; + success "Konsole profiles updated" + ;; + xfce4-terminal) + local xterm_conf="$HOME/.config/xfce4/terminal/terminalrc" + [[ -f "$xterm_conf" ]] && sed -i "s/^FontName=.*/FontName=$FONT_MONO/" "$xterm_conf" + success "XFCE Terminal font updated" + ;; + gnome-terminal) ;; # handled by apply_gnome_fonts via dconf + *) warn "Terminal '$term' font config not supported — set manually" ;; + esac +} + +for term in $TERMINALS; do + apply_terminal_font "$term" +done + +# --- fontconfig fallback (monospace alias) --- +sudo tee /etc/fonts/local.conf > /dev/null < + + + + monospace + + ${FONT_ALIAS} + + + + Hack Nerd Font Mono + + ${FONT_ALIAS} + + + +FONTCONF +sudo fc-cache -f +success "fontconfig monospace alias set" + +# NOTE: TTY/vconsole fonts must be bitmap/psf fonts — Nerd Font TTFs +# cannot be used in vconsole.conf. Skipping to avoid breaking TTY. + +# ============================================================================= +# 5. INSTALL ZSH +# ============================================================================= +step "Installing Zsh" +if ! command -v zsh >/dev/null 2>&1; then + pkg_install zsh + success "Zsh installed" +else + success "Zsh already installed: $(zsh --version)" +fi + +# ============================================================================= +# 6. UPDATE RUBYGEMS + INSTALL COLORLS +# ============================================================================= +step "Setting up Ruby gems (colorls)" +export GEM_HOME="$HOME/.gem" +export PATH="$PATH:$GEM_HOME/bin" +USER_GEM_BIN="$(ruby -e 'puts Gem.user_dir' 2>/dev/null)/bin" + +# Update gems — skip system update on apt (breaks Debian policy) +if [[ "$PM" != "apt" ]]; then + gem update --system 2>/dev/null && success "RubyGems system updated" \ + || warn "RubyGems system update failed — continuing" +fi +gem update 2>/dev/null && success "All gems updated" || warn "gem update had warnings — continuing" + +if gem list -i colorls >/dev/null 2>&1; then + success "colorls already installed" +else + info "Installing colorls..." + gem install --user-install colorls || die "colorls install failed" + success "colorls installed" +fi + +# Add gem bin to PATH in both .zshrc and .bashrc so it works during this session too +for rc in "$HOME/.zshrc" "$HOME/.bashrc"; do + if [[ -f "$rc" ]] && ! grep -q "$USER_GEM_BIN" "$rc" 2>/dev/null; then + echo "export PATH=\"\$PATH:$USER_GEM_BIN\"" >> "$rc" + info "Added gem bin to PATH in $rc" + fi +done +export PATH="$PATH:$USER_GEM_BIN" + +# ============================================================================= +# 7. INSTALL FASTFETCH +# ============================================================================= +step "Installing fastfetch" +if command -v fastfetch >/dev/null 2>&1; then + success "fastfetch already installed: $(fastfetch --version 2>/dev/null | head -1)" +else + info "Trying package manager first..." + installed=false + case "$PM" in + pacman) sudo pacman -S --noconfirm --needed fastfetch 2>/dev/null && installed=true ;; + apt) + # fastfetch not in standard apt — try PPA or direct .deb download + if sudo add-apt-repository -y ppa:zhangsongcui3371/fastfetch 2>/dev/null; then + sudo apt update && sudo apt install -y fastfetch && installed=true + fi ;; + dnf) sudo dnf install -y fastfetch 2>/dev/null && installed=true ;; + zypper) sudo zypper install -y fastfetch 2>/dev/null && installed=true ;; + apk) sudo apk add fastfetch 2>/dev/null && installed=true ;; + esac + + if [[ "$installed" == false ]]; then + warn "Package manager install failed — downloading latest binary release..." + ARCH=$(uname -m) + [[ "$ARCH" == "x86_64" ]] && ARCH_NAME="amd64" || ARCH_NAME="$ARCH" + FF_URL=$(curl -s https://api.github.com/repos/fastfetch-cli/fastfetch/releases/latest \ + | grep "browser_download_url" \ + | grep "linux-${ARCH_NAME}.tar.gz" \ + | head -1 | cut -d'"' -f4) + if [[ -n "$FF_URL" ]]; then + FF_TMP=$(mktemp -d) + curl -fsSL "$FF_URL" -o "$FF_TMP/fastfetch.tar.gz" + tar -xzf "$FF_TMP/fastfetch.tar.gz" -C "$FF_TMP" + sudo install -m755 "$FF_TMP"/fastfetch*/usr/bin/fastfetch /usr/local/bin/fastfetch 2>/dev/null \ + || sudo cp "$(find "$FF_TMP" -name fastfetch -type f | head -1)" /usr/local/bin/fastfetch + sudo chmod +x /usr/local/bin/fastfetch + rm -rf "$FF_TMP" + installed=true + fi + fi + + if [[ "$installed" == true ]] && command -v fastfetch >/dev/null 2>&1; then + success "fastfetch installed: $(fastfetch --version 2>/dev/null | head -1)" + else + warn "fastfetch could not be installed automatically — install it manually" + fi +fi + +# ============================================================================= +# 8. INSTALL OH MY ZSH +# ============================================================================= +step "Installing Oh My Zsh" +if [[ -f "$HOME/.oh-my-zsh/oh-my-zsh.sh" ]]; then + success "Oh My Zsh already installed" +else + info "Installing Oh My Zsh..." + rm -rf "$HOME/.oh-my-zsh" + RUNZSH=no KEEP_ZSHRC=yes \ + sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" \ + || die "Oh My Zsh install failed" + success "Oh My Zsh installed" +fi + +ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}" + +# ============================================================================= +# 9. INSTALL POWERLEVEL10K +# ============================================================================= +step "Installing Powerlevel10k theme" +P10K_DIR="$ZSH_CUSTOM/themes/powerlevel10k" +if [[ -d "$P10K_DIR" ]]; then + info "Updating Powerlevel10k..." + git -C "$P10K_DIR" pull --ff-only 2>/dev/null && success "Powerlevel10k updated" || warn "p10k update failed — skipping" +else + git clone --depth=1 https://github.com/romkatv/powerlevel10k.git "$P10K_DIR" \ + || die "Powerlevel10k install failed" + success "Powerlevel10k installed" +fi + +# ============================================================================= +# 10. INSTALL ZSH PLUGINS +# ============================================================================= +step "Installing Zsh plugins" +declare -A ZSH_PLUGINS=( + [zsh-autosuggestions]="https://github.com/zsh-users/zsh-autosuggestions" + [zsh-syntax-highlighting]="https://github.com/zsh-users/zsh-syntax-highlighting" + [zsh-completions]="https://github.com/zsh-users/zsh-completions" +) + +for plugin in "${!ZSH_PLUGINS[@]}"; do + local_dir="$ZSH_CUSTOM/plugins/$plugin" + if [[ -d "$local_dir" ]]; then + git -C "$local_dir" pull --ff-only 2>/dev/null && success "$plugin updated" || warn "$plugin update skipped" + else + info "Installing $plugin..." + git clone "${ZSH_PLUGINS[$plugin]}" "$local_dir" || warn "$plugin install failed — continuing" + success "$plugin installed" + fi +done + +# ============================================================================= +# 11. COPY .zshrc AND .p10k.zsh +# ============================================================================= +step "Applying .zshrc and .p10k.zsh" +# Use the directory where THIS script lives as the source +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +copy_if_exists() { + local src="$1" dst="$2" label="$3" + if [[ -f "$src" ]]; then + cp "$src" "$dst" + success "$label → $dst" + else + warn "$src not found — $label not copied" + fi +} + +copy_if_exists "$SCRIPT_DIR/.zshrc" "$HOME/.zshrc" ".zshrc" +copy_if_exists "$SCRIPT_DIR/.p10k.zsh" "$HOME/.p10k.zsh" ".p10k.zsh" + +# Ensure gem bin and zsh path are in the copied .zshrc +for line in \ + "export PATH=\"\$PATH:$USER_GEM_BIN\"" \ + "export GEM_HOME=\"\$HOME/.gem\""; do + grep -qF "$line" "$HOME/.zshrc" 2>/dev/null || echo "$line" >> "$HOME/.zshrc" +done + +# ============================================================================= +# 12. SET ZSH AS DEFAULT SHELL +# ============================================================================= +step "Setting Zsh as default shell" +ZSH_PATH=$(command -v zsh) +if [[ "$SHELL" == "$ZSH_PATH" ]]; then + success "Zsh is already the default shell" +else + # Make sure zsh is in /etc/shells + grep -qxF "$ZSH_PATH" /etc/shells || echo "$ZSH_PATH" | sudo tee -a /etc/shells + if chsh -s "$ZSH_PATH" 2>/dev/null; then + success "Default shell set to $ZSH_PATH" + info "Log out and back in for the shell change to take effect" + else + warn "Could not change default shell — run manually: chsh -s $ZSH_PATH" + fi +fi + +# ============================================================================= +# DONE +# ============================================================================= +echo "" +echo -e "${LINE}" +echo -e "${BOLD}${GREEN} ✅ StianNOR Zsh + Nerd Font Setup Complete!${RESET}" +echo -e "${LINE}" +echo -e " ${CYAN}Font:${RESET} Hack Nerd Font installed system-wide" +echo -e " ${CYAN}Shell:${RESET} Zsh + Oh My Zsh + Powerlevel10k" +echo -e " ${CYAN}Plugins:${RESET} autosuggestions, syntax-highlighting, completions" +echo -e " ${CYAN}Tools:${RESET} colorls, fastfetch" +echo -e "${LINE}" +echo -e " ${YELLOW}Next steps:${RESET}" +echo -e " 1. Log out and back in (shell change + font)" +echo -e " 2. Run ${CYAN}p10k configure${RESET} to set up your prompt" +echo -e " 3. In your terminal settings, select ${CYAN}Hack Nerd Font${RESET} manually if needed" +echo -e "${LINE}" +echo ""