3.2 - Assign ZSH Aliases
Step 1 - Open your terminal and type:
sudo pacman -S --needed --noconfirm kate && kate ~/.zshrc
Step 2 - Delete everything and paste the following block:
# ~/.zshrc
# ============================================================================
# Manjaro Linux KDE - Zsh Configuration
# ============================================================================
# Custom configuration for Manjaro Linux with comprehensive system management,
# development tools, and maintenance utilities. All custom commands/functions
# are prefixed with 'x' for easy identification and tab completion.
#
# QUICK REFERENCE - ALL AVAILABLE COMMANDS
# ============================================================================
#
# DNS MANAGEMENT
# dns_status [options] - Comprehensive DNS configuration checker
# dns_s - Quick DNS status check
# dns_v - Verbose DNS status
# dns_l - DNS status with leak tests
#
# FILE & SYSTEM OPERATIONS
# xlock <file> - Make file immutable (chattr +i)
# xunlock <file> - Make file mutable (chattr -i)
# xedit <file(s)> - Smart editor (auto-detects sudo need)
# xedit_hosts - Edit /etc/hosts with sudo
# xedit_zsh - Edit this ~/.zshrc file
# xcombine_md_rec - Combine Markdown files recursively
# xconvert_md - Convert Markdown using Quarto
# xhr - Print horizontal rule separator
# xclear - Clear terminal (full reset)
#
# IMAGE OPTIMIZATION
# xoptimize_img - Optimize images and convert to webp
# xoptimize_rec_img - Optimize images recursively
#
# PACKAGE MANAGEMENT
# xinstall <pkg> - Install package(s) via yay (skip if exists)
# xreinstall <pkg> - Reinstall package(s) via yay
# xremove <pkg> - Remove package(s) and dependencies
# xupdate - Full system update (yay, flatpak, kernels, etc)
# xclean - Aggressive system cache cleaning
# xclean_zsh - Clear Zsh history file
# xpacman_unlock - Remove pacman lock file
# xtunemirrors - Optimize Manjaro mirror list
# xfixkeys - Refresh pacman keys and keyrings
#
# DEVELOPMENT & WEB
# xwget <url> - Mirror/download entire website
# xserve [dir] [port] - Serve static files (default: ./build or ./dist)
# xserver - Simple Python HTTP server on port 8080
# xpyenv_activate - Create/activate Python venv in current dir
# xbun_build - Update and build a JS/TS based bun bundled project -
# xnpm_update - Update npm packages using ncu
# xlampp - Launch XAMPP control panel
# jcurl - Pretty-print JSON from curl using jq
#
# ASTRO.JS WORKFLOWS
# xastro_dev - Start dev server (no clean/build)
# xastro_live - Clean + upgrade + build + dev server
# xastro_preview - Start preview server (no build)
# xastro_build - Clean + upgrade + install + lint + typecheck + build + preview
# xastro_clean - Clean build artifacts (.astro, dist)
# xastro_update - Update dependencies with npm-check-updates
# xastro_check - Project health check & outdated packages
# xastro_quick - Update + install + lint + typecheck + build + preview
# xastro_nuke - Nuclear: delete all + reinstall + lint + typecheck + build + preview
#
# DOCKER MANAGEMENT
# xenable_docker - Enable and start Docker service
# xstop_docker - Stop Docker service
# xstop_docker_autostart - Disable Docker auto-start
# xdelete_docker - DESTRUCTIVE: Remove all containers/images/volumes
#
# SYSTEM FIXES & DIAGNOSTICS
# xfixaudio - Reset PulseAudio (clear config, reinstall)
# xfixpoedit - Rebuild fontconfig caches
# xfixsearch - Enable and check KDE Baloo file indexer
# xfixkeys - Refresh pacman keys and keyrings
# xinfo - Display system info (fastfetch, inxi, display)
#
# COMBINED OPERATIONS
# xoff - Update + Clean + Poweroff
# xmaid - Update + Clean + Clear History + Poweroff
#
# ============================================================================
# ============================================================================
# INITIAL CONFIGURATION
# ============================================================================
# Enable extended pattern matching (globbing) features
setopt extendedglob
# Source Manjaro's default Zsh configuration (prompt, completion, etc)
if [[ -e /usr/share/zsh/manjaro-zsh-config ]]; then
source /usr/share/zsh/manjaro-zsh-config
fi
# ============================================================================
# ENVIRONMENT VARIABLES & PATH
# ============================================================================
# NVM directory for Node Version Manager
export NVM_DIR="$HOME/.nvm"
# bat pager configuration
export PAGER='bat'
# Configure PATH with user bin directories (Zsh-native with uniqueness)
typeset -U path PATH
path=(
"$HOME/.local/bin"
"$HOME/bin"
"$HOME/.opencode/bin"
$path
)
# Remove non-existent directories from PATH
# Zsh glob qualifier: (N-/) = Null if no match, directories only
path=(${^path}(N-/))
# ============================================================================
# NVM INITIALIZATION
# ============================================================================
# Note: NVM's bash_completion works in Zsh but isn't ideal. Sourced after
# PATH setup but before functions that depend on Node/npm.
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
# ============================================================================
# BUN INITIALIZATION
# ============================================================================
# bun
export BUN_INSTALL="${BUN_INSTALL:-$HOME/.bun}"
export PATH="$BUN_INSTALL/bin:$PATH"
# bun completions
[ -s "$BUN_INSTALL/_bun" ] && source "$BUN_INSTALL/_bun"
# ============================================================================
# HELPER FUNCTIONS (INTERNAL USE)
# ============================================================================
# xget_editor - Detect available editor with support for args and full paths
# Returns editor command as array via Zsh's special $reply variable
# Priority: $VISUAL > $EDITOR > subl > kate > micro > nano > vim > vi
xget_editor() {
local -a editor
if [[ -n "$VISUAL" ]]; then
editor=(${=VISUAL})
elif [[ -n "$EDITOR" ]]; then
editor=(${=EDITOR})
fi
if (( ${#editor} )); then
if (( $+commands[$editor[1]] )) || [[ -x "$editor[1]" ]]; then
reply=("${editor[@]}")
return 0
fi
fi
local e
for e in subl kate micro nano vim vi; do
if (( $+commands[$e] )); then
reply=("$e")
return 0
fi
done
return 1
}
# xrun_yay - Helper function to ensure yay is available
xrun_yay() {
if ! (( $+commands[yay] )); then
print -u2 "yay command not found. Please install yay."
return 1
fi
yay "$@"
}
# ============================================================================
# DNS MANAGEMENT
# ============================================================================
dns_status() {
local interface=""
local verbose=false
local run_leak_test=false
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-i|--interface)
interface="$2"
shift 2
;;
-v|--verbose)
verbose=true
shift
;;
-l|--leak-test)
run_leak_test=true
shift
;;
-h|--help)
print "Usage: dns-status [OPTIONS]"
print ""
print "Options:"
print " -i, --interface IFACE Specify network interface for tcpdump tests"
print " -v, --verbose Show detailed output"
print " -l, --leak-test Run tcpdump leak tests (requires sudo)"
print " -h, --help Show this help message"
print ""
print "Examples:"
print " dns-status # Basic status check"
print " dns-status -v # Verbose output"
print " dns-status -l -i enp42s0 # Run leak tests on specific interface"
return 0
;;
*)
print "Unknown option: $1"
print "Use -h for help"
return 1
;;
esac
done
# Colors for output
local RED='\033[0;31m'
local GREEN='\033[0;32m'
local YELLOW='\033[0;33m'
local BLUE='\033[0;34m'
local CYAN='\033[0;36m'
local BOLD='\033[1m'
local NC='\033[0m' # No Color
# Helper functions
_header() {
print ""
print "${BOLD}${BLUE}โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ${NC}"
print "${BOLD}${BLUE} $1${NC}"
print "${BOLD}${BLUE}โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ${NC}"
}
_subheader() {
print ""
print "${BOLD}${CYAN}โถ $1${NC}"
print "${CYAN}โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ${NC}"
}
_success() {
print "${GREEN}โ${NC} $1"
}
_warning() {
print "${YELLOW}โ ${NC} $1"
}
_error() {
print "${RED}โ${NC} $1"
}
_info() {
print "${BLUE}โน${NC} $1"
}
# Auto-detect interface if not specified
if [[ -z "$interface" ]]; then
interface=$(ip route get 1.1.1.1 2>/dev/null | grep -oP 'dev \K\S+' | head -1)
fi
#โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 1: systemd-resolved Status
#โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
_header "1. SYSTEMD-RESOLVED STATUS"
_subheader "Service Status"
if systemctl is-active --quiet systemd-resolved; then
_success "systemd-resolved is running"
else
_error "systemd-resolved is NOT running"
print " Run: sudo systemctl enable --now systemd-resolved"
fi
_subheader "Stub Resolver Configuration"
local resolv_target=$(readlink -f /etc/resolv.conf 2>/dev/null)
print " /etc/resolv.conf โ $resolv_target"
if [[ "$resolv_target" == "/run/systemd/resolve/stub-resolv.conf" ]]; then
_success "Correctly configured (stub resolver)"
elif [[ "$resolv_target" == "/run/systemd/resolve/resolv.conf" ]]; then
_warning "Using resolv.conf (apps may bypass DoT)"
print " Recommended: sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf"
else
_error "Non-standard configuration (DoT may be bypassed)"
print " Run: sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf"
fi
_subheader "Resolver Details"
resolvectl status 2>/dev/null | head -20
if $verbose; then
_subheader "Full Resolver Status"
resolvectl status
fi
#โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 2: DNS Configuration Analysis
#โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
_header "2. DNS CONFIGURATION ANALYSIS"
_subheader "Current DNS Servers"
local dns_servers=$(resolvectl status 2>/dev/null | grep -i "DNS Server" | head -5)
if [[ -n "$dns_servers" ]]; then
print "$dns_servers"
# Check for hostname suffix (required for DoT)
if print "$dns_servers" | grep -q '#'; then
_success "DoT hostname suffix detected (certificate validation enabled)"
else
_warning "No DoT hostname suffix found"
print " Example format: 1.1.1.1#cloudflare-dns.com"
fi
else
_error "No DNS servers configured"
fi
_subheader "DNS Security Protocols"
local protocols=$(resolvectl status 2>/dev/null | grep -iE "^\s*(DNS Over TLS|DNSSEC|Protocols)" | head -5)
if [[ -n "$protocols" ]]; then
print "$protocols"
# Check DNSOverTLS
if print "$protocols" | grep -qi "DNSOverTLS.*yes\|+DNSOverTLS"; then
_success "DNS over TLS (DoT) is ENABLED"
else
_warning "DNS over TLS may not be enabled"
fi
# Check DNSSEC
if print "$protocols" | grep -qi "DNSSEC.*yes\|DNSSEC.*supported"; then
_success "DNSSEC validation is ENABLED"
else
_warning "DNSSEC may not be enabled"
fi
fi
_subheader "DNS Domain Routing"
local domains=$(resolvectl status 2>/dev/null | grep -i "DNS Domain" | head -3)
if [[ -n "$domains" ]]; then
print "$domains"
if print "$domains" | grep -q '~\.'; then
_success "All DNS routed through configured servers (~.)"
fi
fi
_subheader "Configuration File"
local config_file="/etc/systemd/resolved.conf.d/secure-dns.conf"
if [[ -f "$config_file" ]]; then
_success "Drop-in config exists: $config_file"
if $verbose; then
print ""
cat "$config_file"
fi
elif [[ -f "/etc/systemd/resolved.conf" ]]; then
_info "Using main config: /etc/systemd/resolved.conf"
if $verbose; then
print ""
grep -v '^#' /etc/systemd/resolved.conf | grep -v '^$'
fi
fi
#โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 3: Network Configuration
#โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
_header "3. NETWORK CONFIGURATION"
_subheader "Active Network Interfaces"
if [[ -n "$interface" ]]; then
_info "Detected/specified interface: $interface"
fi
ip -brief addr show 2>/dev/null | grep -E "^(en|eth|wl)" | head -5
_subheader "IPv6 Status"
local ipv6_disabled=$(cat /proc/sys/net/ipv6/conf/all/disable_ipv6 2>/dev/null)
if [[ "$ipv6_disabled" == "0" ]]; then
_success "IPv6 is ENABLED"
# Check for IPv6 addresses
local ipv6_addrs=$(ip -6 addr show scope global 2>/dev/null | grep inet6 | head -2)
if [[ -n "$ipv6_addrs" ]]; then
_success "Global IPv6 address(es) found"
if $verbose; then
print "$ipv6_addrs"
fi
else
_warning "No global IPv6 addresses (ISP may not support IPv6)"
fi
else
_info "IPv6 is DISABLED"
fi
_subheader "NetworkManager Status"
if systemctl is-active --quiet NetworkManager; then
_success "NetworkManager is running"
print ""
print " Active connections:"
nmcli -t connection show --active 2>/dev/null | while IFS=: read -r name uuid type device; do
print " โข $name ($type) on $device"
done
# Check NetworkManager DNS mode
local nm_dns_mode=$(grep -r "dns=" /etc/NetworkManager/conf.d/ 2>/dev/null | head -1)
if [[ -n "$nm_dns_mode" ]]; then
if print "$nm_dns_mode" | grep -q "systemd-resolved"; then
_success "NetworkManager configured to use systemd-resolved"
else
_info "NetworkManager DNS mode: $nm_dns_mode"
fi
else
_warning "No explicit NetworkManager DNS configuration found"
print " Consider adding: /etc/NetworkManager/conf.d/10-dns-systemd-resolved.conf"
fi
if $verbose; then
print ""
print " Connection DNS settings:"
local active_conn=$(nmcli -t -f NAME connection show --active | head -1)
if [[ -n "$active_conn" ]]; then
nmcli connection show "$active_conn" 2>/dev/null | grep -iE "(dns|ignore-auto-dns)" | head -10
fi
fi
elif systemctl is-active --quiet wicked; then
_info "Using wicked (not NetworkManager)"
else
_warning "Neither NetworkManager nor wicked detected"
fi
#โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 4: DNS Resolution Tests
#โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
_header "4. DNS RESOLUTION TESTS"
_subheader "Basic Resolution Test"
resolvectl flush-caches 2>/dev/null
local test_domain="cloudflare.com"
local query_result=$(resolvectl query "$test_domain" 2>&1)
if print "$query_result" | grep -qE "^$test_domain"; then
_success "DNS resolution working for $test_domain"
print "$query_result" | head -5
else
_error "DNS resolution FAILED for $test_domain"
print "$query_result"
fi
_subheader "DNSSEC Validation Test"
local dnssec_result=$(resolvectl query cloudflare.com 2>&1)
if print "$dnssec_result" | grep -qi "authenticated.*yes"; then
_success "DNSSEC validation working (authenticated: yes)"
else
_warning "DNSSEC authentication not confirmed"
if $verbose; then
print "$dnssec_result" | grep -i auth
fi
fi
_subheader "Encrypted Transport Check"
local transport_result=$(resolvectl query duckduckgo.com 2>&1)
if print "$transport_result" | grep -qi "encrypted.*yes\|local or encrypted.*yes"; then
_success "DNS queries using encrypted transport"
else
_info "Encrypted transport status unclear from output"
fi
if $verbose; then
_subheader "DNSSEC Failure Test (should fail)"
print " Testing dnssec-failed.org (intentionally broken DNSSEC)..."
local fail_result=$(resolvectl query dnssec-failed.org 2>&1)
if print "$fail_result" | grep -qiE "SERVFAIL|failed|error"; then
_success "Correctly rejected invalid DNSSEC"
else
_warning "Invalid DNSSEC was not rejected"
fi
print "$fail_result" | head -3
fi
#โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 5: Port 53 Listener Check
#โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
_header "5. LOCAL DNS LISTENER CHECK"
_subheader "Processes Listening on Port 53"
local port53=$(sudo ss -tulpn 2>/dev/null | grep ':53' || ss -tulpn 2>/dev/null | grep ':53')
if [[ -n "$port53" ]]; then
print "$port53"
if print "$port53" | grep -q "systemd-resolve"; then
_success "Only systemd-resolved listening on port 53"
elif print "$port53" | grep -qE "dnsmasq|unbound|bind|named"; then
_warning "Other DNS service detected (may conflict)"
fi
else
_info "Could not check port 53 listeners (may need sudo)"
fi
#โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 6: Leak Tests (Optional)
#โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
if $run_leak_test; then
_header "6. DNS LEAK TESTS (tcpdump)"
if [[ -z "$interface" ]]; then
_error "No interface detected. Specify with -i <interface>"
return 1
fi
if ! command -v tcpdump &>/dev/null; then
_error "tcpdump not installed"
print " Install: sudo pacman -S tcpdump # or sudo zypper install tcpdump"
return 1
fi
_subheader "Plaintext DNS Leak Test (Port 53)"
_info "Monitoring for unencrypted DNS on $interface..."
resolvectl flush-caches 2>/dev/null
# Run tcpdump in background
local tcpdump_out=$(mktemp)
sudo timeout 8 tcpdump -ni "$interface" 'port 53' -c 10 2>&1 > "$tcpdump_out" &
local tcpdump_pid=$!
sleep 2
resolvectl query www.cloudflare.com &>/dev/null
resolvectl query github.com &>/dev/null
wait $tcpdump_pid 2>/dev/null
local packets=$(grep -oP '\d+(?= packets captured)' "$tcpdump_out" | head -1)
packets=${packets:-0}
if [[ "$packets" -eq 0 ]]; then
_success "No plaintext DNS leaks detected (0 packets on port 53)"
else
_error "PLAINTEXT DNS DETECTED! ($packets packets on port 53)"
cat "$tcpdump_out"
fi
rm -f "$tcpdump_out"
_subheader "Encrypted DNS Test (Port 853)"
_info "Monitoring for DoT traffic on $interface..."
resolvectl flush-caches 2>/dev/null
local tcpdump_out2=$(mktemp)
sudo timeout 8 tcpdump -ni "$interface" 'tcp port 853' -c 10 2>&1 > "$tcpdump_out2" &
local tcpdump_pid2=$!
sleep 2
resolvectl query www.cloudflare.com &>/dev/null
resolvectl query duckduckgo.com &>/dev/null
wait $tcpdump_pid2 2>/dev/null
local packets2=$(grep -oP '\d+(?= packets captured)' "$tcpdump_out2" | head -1)
packets2=${packets2:-0}
if [[ "$packets2" -gt 0 ]]; then
_success "Encrypted DoT traffic detected ($packets2 packets on port 853)"
else
_warning "No DoT traffic captured (may be cached or using different path)"
fi
rm -f "$tcpdump_out2"
fi
#โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 7: Summary
#โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
_header "7. QUICK SUMMARY"
print ""
print " ${BOLD}Service Status${NC}"
systemctl is-active --quiet systemd-resolved && print " systemd-resolved: ${GREEN}running${NC}" || print " systemd-resolved: ${RED}stopped${NC}"
systemctl is-active --quiet NetworkManager && print " NetworkManager: ${GREEN}running${NC}" || print " NetworkManager: ${YELLOW}not running${NC}"
print ""
print " ${BOLD}Security Features${NC}"
resolvectl status 2>/dev/null | grep -qi "DNSOverTLS.*yes\|+DNSOverTLS" && print " DNS over TLS: ${GREEN}enabled${NC}" || print " DNS over TLS: ${YELLOW}check config${NC}"
resolvectl status 2>/dev/null | grep -qi "DNSSEC.*yes\|DNSSEC.*supported" && print " DNSSEC: ${GREEN}enabled${NC}" || print " DNSSEC: ${YELLOW}check config${NC}"
print ""
print " ${BOLD}Configuration${NC}"
[[ "$(readlink -f /etc/resolv.conf)" == "/run/systemd/resolve/stub-resolv.conf" ]] && print " Stub resolver: ${GREEN}correct${NC}" || print " Stub resolver: ${RED}incorrect${NC}"
[[ -f "/etc/systemd/resolved.conf.d/secure-dns.conf" ]] && print " Drop-in config: ${GREEN}present${NC}" || print " Drop-in config: ${YELLOW}not found${NC}"
print ""
print " ${BOLD}Detected Interface${NC}: ${interface:-unknown}"
if ! $run_leak_test; then
print ""
_info "Run with -l flag to perform tcpdump leak tests"
print " Example: dns-status -l -i $interface"
fi
print ""
}
# ============================================================================
# FILE MANAGEMENT
# ============================================================================
# xlock - Make file immutable using chattr +i
xlock() {
if (( ! $# )); then
print -u2 "xlock: Usage: xlock <filename>"
return 1
fi
if [[ ! -e "$1" ]]; then
print -u2 "xlock: Error: File '$1' not found."
return 1
fi
print "Attempting to lock '$1' (make immutable)..."
if sudo chattr +i -- "$1"; then
print "xlock: Successfully locked '$1'."
return 0
else
print -u2 "xlock: Error: Failed to lock '$1'."
return 1
fi
}
# xunlock - Make file mutable using chattr -i
xunlock() {
if (( ! $# )); then
print -u2 "xunlock: Usage: xunlock <filename>"
return 1
fi
if [[ ! -e "$1" ]]; then
print -u2 "xunlock: Error: File '$1' not found."
return 1
fi
print "Attempting to unlock '$1' (make mutable)..."
if sudo chattr -i -- "$1"; then
print "xunlock: Successfully unlocked '$1'."
return 0
else
print -u2 "xunlock: Error: Failed to unlock '$1'."
return 1
fi
}
# xedit - Smart editor with automatic sudo detection
# Detects if file requires root permissions and uses sudoedit accordingly
xedit() {
if (( ! $# )); then
print -u2 "xedit: Usage: xedit <filename> [additional files...]"
return 1
fi
local -a editor_to_use
if ! xget_editor; then
print -u2 "xedit: Error: No suitable editor found."
return 1
fi
editor_to_use=("${reply[@]}")
# Detect if sudo is needed (files in /etc or non-writable)
local use_sudoedit=0
local file
for file in "$@"; do
if [[ "$file" == /etc/* ]]; then
use_sudoedit=1
break
fi
if [[ -e "$file" ]] && [[ ! -w "$file" ]]; then
use_sudoedit=1
break
fi
if [[ ! -e "$file" ]]; then
if [[ "$file" == */* ]] && [[ ! -w "${file:h}" ]]; then
use_sudoedit=1
break
fi
fi
done
if (( use_sudoedit )); then
local editor_str="${(j: :)editor_to_use}"
print "xedit: Using sudoedit (elevated permissions required)..."
EDITOR="$editor_str" sudoedit -- "$@" || {
print -u2 "xedit: Error: sudoedit failed."
return 1
}
else
print "xedit: Opening file(s)..."
"${editor_to_use[@]}" -- "$@" || {
print -u2 "xedit: Error: Failed to open file(s)."
return 1
}
fi
return 0
}
# xedit_hosts - Edit /etc/hosts using sudoedit
xedit_hosts() {
local -a editor_to_use
if ! xget_editor; then
print -u2 "xedit_hosts: Error: No suitable editor found."
return 1
fi
editor_to_use=("${reply[@]}")
local editor_str="${(j: :)editor_to_use}"
print "xedit_hosts: Opening /etc/hosts with $editor_str (via sudoedit)..."
EDITOR="$editor_str" sudoedit -- /etc/hosts || {
print -u2 "xedit_hosts: Error: sudoedit failed."
return 1
}
return 0
}
# xedit_zsh - Edit ~/.zshrc
xedit_zsh() {
local target_file="$HOME/.zshrc"
local -a editor_to_use
if ! xget_editor; then
print -u2 "xedit_zsh: Error: No suitable editor found."
return 1
fi
editor_to_use=("${reply[@]}")
print "xedit_zsh: Opening '$target_file'..."
"${editor_to_use[@]}" -- "$target_file" || {
print -u2 "xedit_zsh: Error: Failed to open '$target_file'."
return 1
}
return 0
}
# xcombine_md_rec - Combine Markdown files recursively
xcombine_md_rec() {
find . -name "*.md" -sort | xargs pandoc -s -o combined.md
}
# xconvert_md - Convert Markdown using Quarto
xconvert_md() {
local files=( *.qmd(N) )
(( ${#files} )) || {
print "No .qmd files found"
return 1
}
for f in "${files[@]}"; do
print "Rendering $f"
quarto render "$f" "$@"
done
}
# ============================================================================
# IMAGE OPTIMIZATION
# ============================================================================
# xoptimize_img - Optimize images and convert to webp format in the same folder
xoptimize_img() {
for i in *.(png|jpg|jpeg|webp|tiff|bmp)(N); do
print "Processing $i..."
nice -n 19 cwebp -lossless -m 6 "$i" -o "${i%.*}.tmp.webp" && mv "${i%.*}.tmp.webp" "${i%.*}.webp"
done
}
# xoptimize_rec_img - Optimize images and convert to webp format recursively
xoptimize_rec_img() {
for i in **/*.(png|jpg|jpeg|webp|tiff|bmp)(N); do
print "Processing $i..."
nice -n 19 cwebp -lossless -m 6 -mt "$i" -o "${i%.*}.tmp.webp" && mv "${i%.*}.tmp.webp" "${i%.*}.webp"
done
}
# ============================================================================
# PACKAGE MANAGEMENT
# ============================================================================
# xinstall - Install packages (skip if already installed)
xinstall() { xrun_yay -S --needed "$@"; }
# xreinstall - Force reinstall packages
xreinstall() { xrun_yay -S "$@"; }
# xremove - Remove packages with dependencies
xremove() { xrun_yay -Rns "$@"; }
# xclean_zsh - Clear Zsh history file
xclean_zsh() {
local hf="${HISTFILE:-$HOME/.zsh_history}"
print "Clearing Zsh history file ($hf)..."
: >| "$hf" || { print -u2 "xclean_zsh: Failed to truncate $hf"; return 1; }
fc -R "$hf" || { print -u2 "xclean_zsh: Failed to re-read history"; return 1; }
print "Zsh history cleared successfully."
return 0
}
# xclean - Comprehensive and aggressive system cache cleaning
# NOTE: Intentionally aggressive per user preference (pacman -Scc removes ALL cache)
xclean() {
print "Starting comprehensive system clean..."
local hr="=========================================="
print "$hr"
print "Cleaning pacman cache (keeping last 1 version)..."
if (( $+commands[paccache] )); then
sudo paccache -rk1 && print "โ Pacman cache cleaned." || print -u2 "โ paccache failed."
else
print -u2 "โ paccache not found (install pacman-contrib)."
fi
print "$hr"
print "Cleaning ALL pacman cache and unused sync databases..."
if (( $+commands[pacman] )); then
sudo pacman -Scc --noconfirm && print "โ Pacman cache purged." || print -u2 "โ pacman -Scc failed."
else
print -u2 "โ pacman not found."
fi
if (( $+commands[yay] )); then
print "$hr"
print "Cleaning unneeded yay dependencies..."
yay -Yc --noconfirm && print "โ Yay dependencies cleaned." || print -u2 "โ yay -Yc failed."
print "$hr"
print "Cleaning yay build cache..."
yay -Sc --noconfirm && print "โ Yay build cache cleaned." || print -u2 "โ yay -Sc failed."
else
print "$hr"
print -u2 "โ yay not found, skipping yay cache cleaning."
fi
local pamac_dir="/var/tmp/pamac-build-$USER/"
print "$hr"
print "Checking pamac build directory..."
if [[ -d "$pamac_dir" ]]; then
sudo rm -rf -- "${pamac_dir:?}"/* && print "โ Pamac build files cleaned." || print -u2 "โ Failed to clean pamac dir."
else
print "โ Pamac build directory not found (nothing to clean)."
fi
print "$hr"
print "System cleaning finished."
return 0
}
# xupdate - Comprehensive system update (all packages, kernels, tools)
# Uses pipefail to catch curl|bash failures
xupdate() {
setopt local_options pipefail
local hr="=========================================="
print "Starting full system update..."
# System packages via yay
print "$hr"
print "Updating main system packages..."
if (( $+commands[yay] )); then
yay -Syyu --devel --timeupdate --needed --noconfirm && print "โ System updated." || print -u2 "โ yay update failed."
else
print -u2 "โ yay not found."
fi
# Kernel updates (stable + LTS)
print "$hr"
print "Updating kernels (stable + LTS)..."
if (( $+commands[yay] )); then
yay -S --needed --noconfirm linux linux-headers && print "โ Stable kernel updated." || print -u2 "โ Stable kernel update failed."
yay -S --needed --noconfirm linux-lts && print "โ LTS kernel updated." || print -u2 "โ LTS kernel update failed."
fi
# Flatpak
print "$hr"
print "Updating Flatpak packages..."
if (( $+commands[flatpak] )); then
flatpak update --noninteractive --assumeyes && print "โ Flatpak updated." || print -u2 "โ Flatpak update failed."
else
print -u2 "โ Flatpak not found."
fi
# Astral tools (Ruff & uv)
print "$hr"
print "Updating Astral tools (Ruff & uv)..."
if (( $+commands[curl] )); then
curl -LsSf https://astral.sh/ruff/install.sh | sh && print "โ Ruff updated." || print -u2 "โ Ruff update failed."
curl -LsSf https://astral.sh/uv/install.sh | sh && print "โ uv updated." || print -u2 "โ uv update failed."
else
sudo pacman -S --needed --noconfirm curl || print -u2 "โ Could not install curl."
fi
# NVM, Node.js, and npm
print "$hr"
print "Updating NVM, Node.js, and npm..."
export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
mkdir -p "$NVM_DIR"
if (( $+commands[curl] )) && (( $+commands[bash] )); then
if curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash; then
print "โ NVM installer executed."
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
else
print -u2 "โ NVM installer failed."
fi
fi
local nvm_commands="
export NVM_DIR=\"${NVM_DIR}\";
[ -s \"\$NVM_DIR/nvm.sh\" ] && \. \"\$NVM_DIR/nvm.sh\";
[ -s \"/usr/share/nvm/nvm.sh\" ] && \. \"/usr/share/nvm/nvm.sh\";
if typeset -f nvm >/dev/null 2>&1; then
nvm install node || exit 1;
nvm install --lts || exit 1;
nvm alias default 'lts/*' || exit 1;
nvm use default || exit 1;
nvm install-latest-npm || exit 1;
echo \"โ Node.js: \$(node -v), npm: \$(npm -v)\";
exit 0;
else
echo 'โ NVM not available in subshell.' >&2;
exit 1;
fi
"
if zsh -i -c "$nvm_commands"; then
print "โ Node.js/npm updated successfully."
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
else
print -u2 "โ Node.js/npm update encountered errors."
fi
# WP-CLI
print "$hr"
print "Checking WP-CLI..."
if (( $+commands[wp] )); then
if wp cli update --allow-root --yes >/tmp/wpcli-update.log 2>&1; then
print "โ WP-CLI updated."
else
if grep -q -E "already up to date|package manager" /tmp/wpcli-update.log; then
print "โ WP-CLI already up to date."
else
print -u2 "โ WP-CLI update failed."
fi
fi
else
print "โ WP-CLI not installed (skipped)."
fi
print "$hr"
print "Full system update complete."
return 0
}
# xpacman_unlock - Remove pacman lock file
xpacman_unlock() {
if sudo rm -f /var/lib/pacman/db.lck; then
print "โ Pacman unlocked."
return 0
else
print -u2 "โ Failed to unlock pacman."
return 1
fi
}
# xtunemirrors - Optimize Manjaro mirror list
xtunemirrors() {
print "Optimizing mirrors..."
if sudo pacman-mirrors --fasttrack; then
if (( $+commands[yay] )); then
yay -Syyu --noconfirm
fi
print "โ Mirrors optimized."
return 0
else
print -u2 "โ Mirror optimization failed."
return 1
fi
}
# xfixkeys - Refresh pacman keys and keyrings
xfixkeys() {
print "Refreshing pacman keys..."
if sudo pacman-key --init && \
sudo pacman-key --populate archlinux manjaro && \
sudo pacman-key --refresh-keys && \
sudo pacman -Sy --noconfirm archlinux-keyring manjaro-keyring; then
print "โ Pacman keys refreshed."
return 0
else
print -u2 "โ Key refresh failed."
return 1
fi
}
# ============================================================================
# WEB & DOWNLOAD FUNCTIONS
# ============================================================================
# xwget - Mirror/download entire website with polite settings
xwget() {
if (( ! $# )); then
print -u2 "xwget: Usage: xwget <URL>"
return 1
fi
local url="$1"
local site_name
local output_base_dir="$HOME/Downloads/MirroredSites"
local output_dir
# Extract and sanitize site name from URL
site_name=$(print "$url" | sed -E 's#^([a-zA-Z.+-]+:)?(//)?([^/?#]+).*#\3#' | sed 's/[^a-zA-Z0-9._-]/_/g')
if [[ -z "$site_name" ]]; then
site_name="unknown_site_$(date +%s)"
print -u2 "xwget: Warning: Using fallback name '$site_name'."
fi
output_dir="$output_base_dir/$site_name"
if ! mkdir -p "$output_dir"; then
print -u2 "xwget: Error: Failed to create output directory."
return 1
fi
print "Mirroring '$url' to '$output_dir'..."
if wget --mirror --convert-links --adjust-extension --page-requisites \
--no-parent --wait=1 --random-wait --limit-rate=200k \
--user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0" \
-P "$output_dir" "$url"; then
print "xwget: Download completed successfully."
return 0
else
print -u2 "xwget: Error: wget failed."
return 1
fi
}
# xserve - Serve static files via npm's 'serve' package
# Auto-detects ./build or ./dist directories
xserve() {
local serve_dir="${1:-.}"
local port="${2:-3000}"
if ! (( $+commands[serve] )); then
print "xserve: 'serve' not found. Attempting to install..."
if ! (( $+commands[npm] )); then
print -u2 "xserve: Error: npm not found. Install Node.js first."
return 1
fi
if ! npm install -g "serve"; then
print -u2 "xserve: Error: Failed to install 'serve'."
return 1
fi
print "xserve: 'serve' installed successfully."
fi
local actual_serve_dir="$serve_dir"
if [[ "$serve_dir" == "." ]]; then
if [[ -d "./build" ]]; then
actual_serve_dir="./build"
print "xserve: Auto-detected './build' directory."
elif [[ -d "./dist" ]]; then
actual_serve_dir="./dist"
print "xserve: Auto-detected './dist' directory."
else
print "xserve: Serving current directory."
fi
fi
print "xserve: Starting server at http://localhost:$port ..."
serve -s "$actual_serve_dir" -l "$port" || {
print -u2 "xserve: Error: 'serve' command failed."
return 1
}
return 0
}
# xserver - Simple Python HTTP server on port 8080
xserver() {
if (( $+commands[python3] )); then
print "Starting Python HTTP server on port 8080..."
python3 -m http.server 8080
else
print -u2 "โ python3 not found."
return 1
fi
}
# ============================================================================
# PYTHON DEVELOPMENT
# ============================================================================
# xpyenv_activate - Create and/or activate Python virtual environment
# Creates 'venv' directory if it doesn't exist, activates otherwise
xpyenv_activate() {
local venv_dir="venv"
local activate_script="$venv_dir/bin/activate"
local log_file="venv-creation.log"
if ! (( $+commands[python3] )); then
print -u2 "xpyenv_activate: Error: python3 not found."
return 1
fi
if [[ -d "$venv_dir" ]]; then
if [[ -f "$activate_script" ]]; then
print "xpyenv_activate: Activating existing venv..."
if source "$activate_script"; then
print "xpyenv_activate: Venv activated successfully."
return 0
else
print -u2 "xpyenv_activate: ERROR: Activation failed."
return 1
fi
else
print -u2 "xpyenv_activate: ERROR: '$venv_dir' exists but activate script missing."
print -u2 "Delete '$venv_dir' and try again."
return 1
fi
else
print "xpyenv_activate: Creating new venv (logs to '$log_file')..."
if python3 -m venv "$venv_dir" 2> >(tee "$log_file" >&2); then
print "xpyenv_activate: Venv created successfully."
if [[ -f "$activate_script" ]]; then
if source "$activate_script"; then
print "xpyenv_activate: New venv activated successfully."
return 0
else
print -u2 "xpyenv_activate: ERROR: Failed to activate new venv."
return 1
fi
else
print -u2 "xpyenv_activate: ERROR: Activate script missing after creation."
return 1
fi
else
print -u2 "xpyenv_activate: ERROR: Failed to create venv. Check '$log_file'."
return 1
fi
fi
}
# ============================================================================
# DOCUSAURUS DEVELOPMENT
# ============================================================================
# xbun_build - Update and build JS/TS bun bundled project
xbun_build() {
xhr
# 1. Check if Bun is installed
if ! (( $+commands[bun] )); then
print -u2 "xbun_build: Error: bun not found."
return 1
fi
# 2. Smart Version Check (Once per session)
if [[ -z "$_XBUN_UPDATE_CHECKED" ]]; then
autoload -Uz is-at-least
local current_ver="$(bun --version)"
print "Checking for Bun updates (Current: v$current_ver)..."
local latest_tag latest_ver
latest_tag=$(curl -fsS --max-time 2 \
https://api.github.com/repos/oven-sh/bun/releases/latest \
| sed -n 's/.*"tag_name":[[:space:]]*"\([^"]*\)".*/\1/p')
latest_ver="${latest_tag#bun-v}"
if [[ -n "$latest_ver" ]] && ! is-at-least "$latest_ver" "$current_ver"; then
print "โค New version found ($latest_ver). Upgrading Bun..."
bun upgrade || { print -u2 "โ Bun upgrade failed."; return 1; }
else
print "โ Bun is up to date."
fi
export _XBUN_UPDATE_CHECKED=1
else
print "โ Bun update check skipped (already checked this session)."
fi
# 3. Update dependencies with npm-check-updates
xhr
print "๐ฆ Updating dependencies with npm-check-updates..."
bunx ncu -u || { print -u2 "โ Dependency update failed."; return 1; }
# 4. Install updated dependencies
xhr
print "๐ฅ Installing dependencies..."
bun install || { print -u2 "โ Dependency install failed."; return 1; }
# 5. Lint code
xhr
print "๐ Linting code..."
bun run lint || { print -u2 "โ Lint failed."; return 1; }
# 6. Type checking
xhr
print "๐ Type checking..."
bun run typecheck || { print -u2 "โ Type check failed."; return 1; }
# 7. Build site
xhr
print "๐๏ธ Building site..."
bun run build || { print -u2 "โ Build failed."; return 1; }
# 8. Start preview server
xhr
print "๐ Starting preview server..."
bun run preview
}
# xnpm_update - Update npm packages using ncu
xnpm_update() {
print "Checking npm updates with ncu..."
if ! (( $+commands[ncu] )); then
print -u2 "โ ncu not found. Install: npm install -g npm-check-updates"
return 1
fi
if ncu -u && npm install && npm audit fix --force; then
print "โ npm packages updated successfully."
return 0
else
print -u2 "โ npm update failed."
return 1
fi
}
# xlampp - Launch XAMPP control panel
xlampp() {
local xampp_manager="/opt/lampp/manager-linux-x64.run"
if [[ -x "$xampp_manager" ]]; then
sudo "$xampp_manager"
return 0
else
print -u2 "โ XAMPP manager not found at $xampp_manager"
return 1
fi
}
# ============================================================================
# DOCKER MANAGEMENT
# ============================================================================
# xenable_docker - Enable and start Docker service
xenable_docker() {
if sudo systemctl enable --now docker.socket docker.service; then
print "โ Docker enabled and started."
return 0
else
print -u2 "โ Failed to enable Docker."
return 1
fi
}
# xstop_docker_autostart - Disable Docker auto-start
xstop_docker_autostart() {
if sudo systemctl disable docker.socket docker.service; then
print "โ Docker auto-start disabled."
return 0
else
print -u2 "โ Failed to disable Docker auto-start."
return 1
fi
}
# xstop_docker - Stop Docker service
xstop_docker() {
if sudo systemctl stop docker.socket docker.service; then
print "โ Docker stopped."
return 0
else
print -u2 "โ Failed to stop Docker."
return 1
fi
}
# xdelete_docker - DESTRUCTIVE: Remove all Docker containers, images, volumes
# Requires explicit confirmation before proceeding
xdelete_docker() {
if ! (( $+commands[docker] )); then
print -u2 "xdelete_docker: Docker not found."
return 1
fi
print "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
print "WARNING: DESTRUCTIVE OPERATION"
print "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
print "This will:"
print " โข Stop all running containers"
print " โข Remove all containers (stopped and running)"
print " โข Remove all images"
print " โข Remove all volumes"
print " โข Prune all networks and build cache"
print ""
print "This operation is IRREVERSIBLE."
print "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
local confirm
read -k 1 -r "confirm?Are you absolutely sure? (y/N): "
print
if [[ "$confirm" =~ ^[Yy]$ ]]; then
print "Proceeding with Docker cleanup..."
local hr="=========================================="
print "$hr"
print "Stopping all containers..."
docker ps -aq | xargs -r docker stop || print "No containers to stop."
print "$hr"
print "Removing all containers..."
docker ps -aq | xargs -r docker rm || print "No containers to remove."
print "$hr"
print "Pruning Docker system..."
docker system prune -af && print "โ System pruned." || print -u2 "โ System prune failed."
print "$hr"
print "Removing all images..."
docker images -q | xargs -r docker rmi -f || print "No images to remove."
print "$hr"
print "Pruning volumes..."
docker volume prune -f && print "โ Volumes pruned." || print -u2 "โ Volume prune failed."
print "$hr"
print "Removing remaining volumes..."
docker volume ls -q | xargs -r docker volume rm || print "No remaining volumes."
print "$hr"
print "Docker cleanup complete."
print "Current Docker disk usage:"
docker system df
else
print "Docker cleanup cancelled."
fi
return 0
}
# ============================================================================
# SYSTEM FIXES & DIAGNOSTICS
# ============================================================================
# xfixaudio - Reset PulseAudio (clear config, reinstall)
xfixaudio() {
print "Resetting PulseAudio..."
pulseaudio -k &>/dev/null
rm -rf ~/.config/pulse/* ~/.cache/pulse/*
if sudo pacman -S --noconfirm --needed pulseaudio pulseaudio-alsa; then
if pulseaudio --start; then
print "โ PulseAudio reset complete."
print "โ ๏ธ Warning: Not for PipeWire systems"
return 0
fi
fi
print -u2 "โ PulseAudio reset failed."
return 1
}
# xfixpoedit - Rebuild fontconfig caches
xfixpoedit() {
print "Rebuilding fontconfig caches..."
sudo rm -rf /var/cache/fontconfig/*
rm -rf ~/.cache/fontconfig/*
if sudo fc-cache -fsv && fc-cache -fsv; then
print "โ Fontconfig caches rebuilt."
return 0
else
print -u2 "โ Cache rebuild failed."
return 1
fi
}
# xfixsearch - Enable and check KDE Baloo file indexer
xfixsearch() {
if (( $+commands[balooctl6] )); then
print "Using balooctl6 (KDE 6)..."
balooctl6 enable
balooctl6 check
balooctl6 status
return 0
elif (( $+commands[balooctl] )); then
print "Using balooctl (KDE 5)..."
balooctl enable
balooctl check
balooctl status
return 0
else
print -u2 "โ Baloo control not found."
return 1
fi
}
# xinfo - Display comprehensive system information
xinfo() {
print "โโโ Fastfetch โโโ"
if (( $+commands[fastfetch] )); then
fastfetch
else
print -u2 "โ fastfetch not found."
fi
xhr
print "โโโ Inxi โโโ"
if (( $+commands[inxi] )); then
inxi -FGx
else
print -u2 "โ inxi not found."
fi
xhr
print "โโโ Display Info โโโ"
if (( $+commands[xdpyinfo] )); then
xdpyinfo | grep -B2 resolution
else
print -u2 "โ xdpyinfo not found (Wayland or not installed)."
fi
}
# ============================================================================
# COMMAND REPLACEMENTS & ENHANCEMENTS
# ============================================================================
# eza -> ls replacement
alias ls='eza --icons --group-directories-first'
alias ll='eza -lh --icons --group-directories-first'
alias la='eza -a --icons --group-directories-first'
alias tree='eza --tree --icons'
# bat -> cat replacement
alias cat='bat --paging=never'
# gdu -> disk usage tool
alias xdu='gdu'
# bottom -> top replacement
alias top='btm'
# lazygit alias
alias lg='lazygit'
# jcurl - Pretty-print JSON from curl using jq
jcurl() {
curl -sL "$@" | jq
}
# ============================================================================
# SYSTEM ALIASES - UTILITIES
# ============================================================================
xhr() {
printf "%*s\n" "${COLUMNS:-$(tput cols 2>/dev/null || echo 80)}" "" | tr " " "-"
}
xclear() {
tput reset
}
# ============================================================================
# SYSTEM ALIASES - DNS (Simple redirects - kept as aliases)
# ============================================================================
alias dns_s='dns_status'
alias dns_v='dns_status -v'
alias dns_l='dns_status -l'
# ============================================================================
# SYSTEM ALIASES - ASTRO.JS WORKFLOWS
# ============================================================================
# _xastro_detect_pm - Detect and set package manager
_xastro_detect_pm() {
emulate -L zsh
# Check for lockfiles to determine package manager
if [[ -f bun.lockb ]] && command -v bun >/dev/null 2>&1; then
PM="bun"
PMX="bunx"
LOCKFILE="bun.lockb"
elif [[ -f package-lock.json ]] || ! command -v bun >/dev/null 2>&1; then
if ! command -v npm >/dev/null 2>&1; then
print -u2 "โ npm not found. Please install Node.js"
return 1
fi
PM="npm"
PMX="npx"
LOCKFILE="package-lock.json"
elif command -v bun >/dev/null 2>&1; then
# Default to bun if available and no lockfile exists
PM="bun"
PMX="bunx"
LOCKFILE="bun.lockb"
else
PM="npm"
PMX="npx"
LOCKFILE="package-lock.json"
fi
return 0
}
# _xastro_require - Check Astro.js prerequisites
_xastro_require() {
emulate -L zsh
_xastro_detect_pm || return 1
if [[ ! -f package.json ]]; then
print -u2 "โ No package.json found in $PWD"
return 1
fi
print "Using package manager: $PM"
return 0
}
# _xastro_full_workflow - Complete build workflow
_xastro_full_workflow() {
emulate -L zsh
print "๐ Updating package.json..."
$PMX ncu -u || return 1
print "๐ Upgrading Astro..."
$PMX @astrojs/upgrade || return 1
print "๐ฆ Installing dependencies..."
$PM install || return 1
print "๐ Linting code..."
$PM run lint || return 1
print "๐ Type checking..."
$PM run typecheck || return 1
print "๐๏ธ Building site..."
$PM run build || return 1
print "๐ Starting preview server..."
$PM run preview
}
# xastro_update - Update dependencies only
xastro_update() {
emulate -L zsh
_xastro_require || return 1
print "๐ฆ Updating dependencies with npm-check-updates..."
$PMX ncu -u || return 1
print "๐ฅ Installing updated dependencies..."
$PM install || return 1
print "โ Dependencies updated"
}
# xastro_build - Full build + preview
xastro_build() {
emulate -L zsh
_xastro_require || return 1
print "๐งน Cleaning build artifacts..."
rm -rf .astro dist
_xastro_full_workflow
}
# xastro_nuke - Nuclear option: delete everything + full rebuild
xastro_nuke() {
emulate -L zsh
_xastro_require || return 1
print "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
print "๐ฃ NUCLEAR OPTION: Complete Astro.js Rebuild"
print "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
print "This will delete:"
print " โข .astro/"
print " โข dist/"
print " โข node_modules/"
print " โข $LOCKFILE"
print ""
print -n "Continue? (y/N): "
local ans
read -r ans
[[ "$ans" == [Yy] ]] || { print "โ Cancelled."; return 0; }
print "\n๐๏ธ Deleting everything..."
rm -rf -- .astro dist node_modules bun.lockb package-lock.json
_xastro_full_workflow
}
# xastro_live - Quick dev: clean + upgrade + build + dev server
xastro_live() {
emulate -L zsh
_xastro_require || return 1
print "๐งน Cleaning build artifacts..."
rm -rf .astro dist
print "โฌ Upgrading Astro..."
$PMX @astrojs/upgrade
print "๐๏ธ Building site..."
$PM run build
print "๐ฅ Starting development server..."
$PM run dev
}
# xastro_check - Check project health
xastro_check() {
emulate -L zsh
_xastro_require || return 1
print "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
print "๐ฅ Astro.js Project Health Check"
print "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
print "\n๐ $PM version:"
$PM --version
print "\n๐ Package.json info:"
if [[ -f package.json ]]; then
if [[ "$PM" == "bun" ]]; then
bun -e 'const p=require("./package.json"); console.log(p.name, p.version)'
else
node -e 'const p=require("./package.json"); console.log(p.name, p.version)'
fi
fi
print "\n๐ฆ Outdated packages:"
$PMX ncu || return 1
print "\n๐พ Disk usage:"
command du -sh node_modules .astro dist 2>/dev/null || print " No build artifacts found"
print "\n๐ Linting code..."
$PM run lint || print " โ ๏ธ Lint script not available"
print "\n๐ Type checking..."
$PM run typecheck || print " โ ๏ธ Typecheck script not available"
print "\nโ Astro check..."
$PM run astro check || print " โ ๏ธ Astro check not available"
}
# xastro_clean - Just clean, don't build
xastro_clean() {
emulate -L zsh
_xastro_require || return 1
print "๐งน Cleaning Astro build artifacts..."
rm -rf -- .astro dist
print "โ Cleaned .astro/ and dist/"
}
# xastro_dev - Just run dev server (no clean/build)
xastro_dev() {
emulate -L zsh
_xastro_require || return 1
print "๐ฅ Starting development server..."
$PM run dev
}
# xastro_preview - Just run preview server
xastro_preview() {
emulate -L zsh
_xastro_require || return 1
print "๐ Starting preview server..."
$PM run preview
}
# xastro_quick - Quick workflow: update + lint + typecheck + build + preview
xastro_quick() {
emulate -L zsh
_xastro_require || return 1
print "๐ฆ Updating dependencies..."
$PMX ncu -u || return 1
print "๐ฅ Installing dependencies..."
$PM install || return 1
print "๐ Linting code..."
$PM run lint || return 1
print "๐ Type checking..."
$PM run typecheck || return 1
print "๐๏ธ Building site..."
$PM run build || return 1
print "๐ Starting preview server..."
$PM run preview
}
# ============================================================================
# SYSTEM ALIASES - COMBINED OPERATIONS (Simple chains - kept as aliases)
# ============================================================================
alias xoff='xupdate && xclean && sudo poweroff'
alias xmaid='xupdate && xclean && xclean_zsh && sudo poweroff'
# ============================================================================
# PROMPT INITIALIZATION (MUST BE LAST)
# ============================================================================
if (( $+commands[starship] )); then
eval "$(starship init zsh)"
else
print -u2 "โ Warning: starship not found. Prompt disabled."
fi
# ============================================================================
# END OF CONFIGURATION
# ============================================================================
Step 3 - Apply the changes to the (.zshrc) file:
source ~/.zshrc
3.2.3 - Update The ZSH History Fileโ
The commands history file is found at: ~/.zhistory. Open this file then paste the following inside it:
exa --tree --list
ffmpeg -i input.mp4 -filter:a loudnorm output.mp4
marp input.md -o output.pdf --allow-local-files
bun install --save @easyops-cn/docusaurus-search-local
xupdate