Dotfiles update 2025-12-25 15:45
This commit is contained in:
230
zsh/lib/machines.zsh
Normal file
230
zsh/lib/machines.zsh
Normal file
@@ -0,0 +1,230 @@
|
||||
# ============================================================================
|
||||
# Machine-Specific Configuration Loader
|
||||
# ============================================================================
|
||||
# Automatically loads configuration based on hostname, allowing different
|
||||
# settings per machine while keeping a single dotfiles repository.
|
||||
#
|
||||
# Configuration hierarchy (later files override earlier):
|
||||
# 1. dotfiles.conf (base config)
|
||||
# 2. machines/default.zsh (shared overrides)
|
||||
# 3. machines/<hostname>.zsh (machine-specific)
|
||||
# 4. ~/.zshrc.local (local user overrides)
|
||||
#
|
||||
# Usage:
|
||||
# Create ~/.dotfiles/machines/<hostname>.zsh for machine-specific settings
|
||||
# Use `df_machine_info` to see current machine detection
|
||||
# ============================================================================
|
||||
|
||||
# Prevent double-sourcing
|
||||
[[ -n "$_DF_MACHINES_LOADED" ]] && return 0
|
||||
typeset -g _DF_MACHINES_LOADED=1
|
||||
|
||||
# ============================================================================
|
||||
# Machine Detection
|
||||
# ============================================================================
|
||||
|
||||
typeset -g DF_HOSTNAME="${HOST:-${HOSTNAME:-$(hostname -s 2>/dev/null)}}"
|
||||
typeset -g DF_HOSTNAME_FULL="$(hostname -f 2>/dev/null || echo "$DF_HOSTNAME")"
|
||||
typeset -g DF_MACHINE_TYPE="unknown"
|
||||
typeset -g DF_MACHINE_CONFIG=""
|
||||
|
||||
# Detect machine type based on hostname patterns or hardware
|
||||
_df_detect_machine_type() {
|
||||
local hostname="$DF_HOSTNAME"
|
||||
|
||||
# Check for common naming patterns
|
||||
case "$hostname" in
|
||||
*laptop*|*book*|*portable*|*mobile*)
|
||||
DF_MACHINE_TYPE="laptop"
|
||||
;;
|
||||
*server*|*srv*|*node*|*host*)
|
||||
DF_MACHINE_TYPE="server"
|
||||
;;
|
||||
*desktop*|*workstation*|*ws*|*pc*)
|
||||
DF_MACHINE_TYPE="desktop"
|
||||
;;
|
||||
*vm*|*virtual*|*container*)
|
||||
DF_MACHINE_TYPE="virtual"
|
||||
;;
|
||||
*)
|
||||
# Try to detect from hardware
|
||||
if [[ -d /sys/class/power_supply/BAT0 ]]; then
|
||||
DF_MACHINE_TYPE="laptop"
|
||||
elif [[ -f /proc/cpuinfo ]] && grep -qi "hypervisor\|vmware\|virtualbox\|kvm\|xen" /proc/cpuinfo 2>/dev/null; then
|
||||
DF_MACHINE_TYPE="virtual"
|
||||
elif systemd-detect-virt &>/dev/null && [[ "$(systemd-detect-virt)" != "none" ]]; then
|
||||
DF_MACHINE_TYPE="virtual"
|
||||
else
|
||||
DF_MACHINE_TYPE="desktop"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Configuration Loading
|
||||
# ============================================================================
|
||||
|
||||
_df_load_machine_config() {
|
||||
local machines_dir="${DOTFILES_DIR:-$HOME/.dotfiles}/machines"
|
||||
local loaded=()
|
||||
|
||||
# Create machines directory if it doesn't exist
|
||||
[[ ! -d "$machines_dir" ]] && mkdir -p "$machines_dir"
|
||||
|
||||
# 1. Load default machine config (shared across all machines)
|
||||
if [[ -f "$machines_dir/default.zsh" ]]; then
|
||||
source "$machines_dir/default.zsh"
|
||||
loaded+=("default")
|
||||
fi
|
||||
|
||||
# 2. Load machine-type specific config
|
||||
if [[ -f "$machines_dir/type-${DF_MACHINE_TYPE}.zsh" ]]; then
|
||||
source "$machines_dir/type-${DF_MACHINE_TYPE}.zsh"
|
||||
loaded+=("type-${DF_MACHINE_TYPE}")
|
||||
fi
|
||||
|
||||
# 3. Load hostname-specific config (highest priority)
|
||||
if [[ -f "$machines_dir/${DF_HOSTNAME}.zsh" ]]; then
|
||||
source "$machines_dir/${DF_HOSTNAME}.zsh"
|
||||
loaded+=("$DF_HOSTNAME")
|
||||
DF_MACHINE_CONFIG="$machines_dir/${DF_HOSTNAME}.zsh"
|
||||
fi
|
||||
|
||||
# Store what was loaded for debugging
|
||||
typeset -g DF_MACHINE_CONFIGS_LOADED="${(j:, :)loaded}"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Machine Information Commands
|
||||
# ============================================================================
|
||||
|
||||
# Display machine detection info
|
||||
df_machine_info() {
|
||||
source "${DOTFILES_DIR:-$HOME/.dotfiles}/zsh/lib/bootstrap.zsh" 2>/dev/null
|
||||
|
||||
df_print_func_name "Machine Configuration"
|
||||
echo ""
|
||||
df_print_section "Detection"
|
||||
df_print_indent "Hostname: $DF_HOSTNAME"
|
||||
df_print_indent "Full hostname: $DF_HOSTNAME_FULL"
|
||||
df_print_indent "Machine type: $DF_MACHINE_TYPE"
|
||||
echo ""
|
||||
df_print_section "Loaded Configs"
|
||||
if [[ -n "$DF_MACHINE_CONFIGS_LOADED" ]]; then
|
||||
df_print_indent "$DF_MACHINE_CONFIGS_LOADED"
|
||||
else
|
||||
df_print_indent "(none)"
|
||||
fi
|
||||
echo ""
|
||||
df_print_section "Config File"
|
||||
if [[ -n "$DF_MACHINE_CONFIG" ]]; then
|
||||
df_print_indent "$DF_MACHINE_CONFIG"
|
||||
else
|
||||
df_print_indent "No machine-specific config found"
|
||||
df_print_info "Create: ${DOTFILES_DIR:-$HOME/.dotfiles}/machines/${DF_HOSTNAME}.zsh"
|
||||
fi
|
||||
}
|
||||
|
||||
# Create a new machine config from template
|
||||
df_machine_create() {
|
||||
local hostname="${1:-$DF_HOSTNAME}"
|
||||
local machines_dir="${DOTFILES_DIR:-$HOME/.dotfiles}/machines"
|
||||
local config_file="$machines_dir/${hostname}.zsh"
|
||||
|
||||
source "${DOTFILES_DIR:-$HOME/.dotfiles}/zsh/lib/bootstrap.zsh" 2>/dev/null
|
||||
|
||||
if [[ -f "$config_file" ]]; then
|
||||
df_print_warning "Config already exists: $config_file"
|
||||
df_confirm "Edit existing config?" && ${EDITOR:-vim} "$config_file"
|
||||
return
|
||||
fi
|
||||
|
||||
df_print_step "Creating machine config: $hostname"
|
||||
|
||||
cat > "$config_file" << EOF
|
||||
# ============================================================================
|
||||
# Machine Configuration: ${hostname}
|
||||
# ============================================================================
|
||||
# This file is automatically loaded when the hostname matches.
|
||||
# Created: $(date '+%Y-%m-%d %H:%M')
|
||||
#
|
||||
# Available variables to override:
|
||||
# DF_WIDTH, MOTD_STYLE, ENABLE_MOTD, ZSH_THEME_NAME
|
||||
# Any variable from dotfiles.conf
|
||||
# ============================================================================
|
||||
|
||||
# --- Display Settings ---
|
||||
# DF_WIDTH="80" # Wider terminal?
|
||||
# MOTD_STYLE="mini" # mini, compact, full, none
|
||||
|
||||
# --- Machine-specific paths ---
|
||||
# export PATH="\$HOME/custom-tools:\$PATH"
|
||||
|
||||
# --- Machine-specific aliases ---
|
||||
# alias proj='cd ~/projects/work'
|
||||
|
||||
# --- Machine-specific environment ---
|
||||
# export JAVA_HOME="/usr/lib/jvm/java-17"
|
||||
|
||||
# --- Conditional features ---
|
||||
# Example: Disable heavy features on slow machines
|
||||
# ENABLE_SMART_SUGGESTIONS="false"
|
||||
|
||||
# --- SSH agent (if needed on this machine) ---
|
||||
# if [[ -z "\$SSH_AUTH_SOCK" ]]; then
|
||||
# eval "\$(ssh-agent -s)" &>/dev/null
|
||||
# ssh-add ~/.ssh/id_ed25519 2>/dev/null
|
||||
# fi
|
||||
|
||||
# --- Custom startup commands ---
|
||||
# echo "Welcome to ${hostname}!"
|
||||
EOF
|
||||
|
||||
df_print_success "Created: $config_file"
|
||||
df_print_info "Edit with: ${EDITOR:-vim} $config_file"
|
||||
|
||||
df_confirm "Edit now?" && ${EDITOR:-vim} "$config_file"
|
||||
}
|
||||
|
||||
# List all machine configs
|
||||
df_machine_list() {
|
||||
local machines_dir="${DOTFILES_DIR:-$HOME/.dotfiles}/machines"
|
||||
|
||||
source "${DOTFILES_DIR:-$HOME/.dotfiles}/zsh/lib/bootstrap.zsh" 2>/dev/null
|
||||
|
||||
df_print_func_name "Machine Configurations"
|
||||
echo ""
|
||||
|
||||
if [[ ! -d "$machines_dir" ]] || [[ -z "$(ls -A "$machines_dir" 2>/dev/null)" ]]; then
|
||||
df_print_info "No machine configs found"
|
||||
df_print_info "Create one: df_machine_create <hostname>"
|
||||
return
|
||||
fi
|
||||
|
||||
for config in "$machines_dir"/*.zsh(N); do
|
||||
[[ -f "$config" ]] || continue
|
||||
local name=$(basename "$config" .zsh)
|
||||
local marker=""
|
||||
[[ "$name" == "$DF_HOSTNAME" ]] && marker=" ${DF_GREEN}(current)${DF_NC}"
|
||||
[[ "$name" == "default" ]] && marker=" ${DF_CYAN}(shared)${DF_NC}"
|
||||
[[ "$name" == type-* ]] && marker=" ${DF_YELLOW}(type)${DF_NC}"
|
||||
df_print_indent "● ${name}${marker}"
|
||||
done
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Aliases
|
||||
# ============================================================================
|
||||
|
||||
alias machines='df_machine_list'
|
||||
alias machine-info='df_machine_info'
|
||||
alias machine-create='df_machine_create'
|
||||
alias machine-edit='${EDITOR:-vim} "${DOTFILES_DIR:-$HOME/.dotfiles}/machines/${DF_HOSTNAME}.zsh"'
|
||||
|
||||
# ============================================================================
|
||||
# Initialize
|
||||
# ============================================================================
|
||||
|
||||
_df_detect_machine_type
|
||||
_df_load_machine_config
|
||||
301
zsh/lib/plugins.zsh
Normal file
301
zsh/lib/plugins.zsh
Normal file
@@ -0,0 +1,301 @@
|
||||
# ============================================================================
|
||||
# Dotfiles Plugin Manager
|
||||
# ============================================================================
|
||||
# A thin wrapper for managing zsh plugins without heavy frameworks.
|
||||
#
|
||||
# Features:
|
||||
# - Simple git-based plugin installation
|
||||
# - Automatic updates
|
||||
# - Lazy loading support
|
||||
# - Oh-My-Zsh plugin compatibility
|
||||
# ============================================================================
|
||||
|
||||
# Prevent double-sourcing
|
||||
[[ -n "$_DF_PLUGINS_LOADED" ]] && return 0
|
||||
typeset -g _DF_PLUGINS_LOADED=1
|
||||
|
||||
# ============================================================================
|
||||
# Configuration
|
||||
# ============================================================================
|
||||
|
||||
typeset -g DF_PLUGIN_DIR="${DF_PLUGIN_DIR:-$HOME/.dotfiles/zsh/plugins}"
|
||||
typeset -g DF_PLUGIN_REPOS_FILE="${DF_PLUGIN_DIR}/.repos"
|
||||
|
||||
# Track loaded plugins
|
||||
typeset -ga DF_LOADED_PLUGINS=()
|
||||
|
||||
# ============================================================================
|
||||
# Core Functions
|
||||
# ============================================================================
|
||||
|
||||
# Install a plugin from GitHub
|
||||
# Usage: df_plugin "zsh-users/zsh-autosuggestions" [branch]
|
||||
df_plugin() {
|
||||
local repo="$1"
|
||||
local branch="${2:-master}"
|
||||
local name="${repo##*/}"
|
||||
local dir="$DF_PLUGIN_DIR/$name"
|
||||
|
||||
# Ensure plugin directory exists
|
||||
[[ ! -d "$DF_PLUGIN_DIR" ]] && mkdir -p "$DF_PLUGIN_DIR"
|
||||
|
||||
# Clone if not exists
|
||||
if [[ ! -d "$dir" ]]; then
|
||||
echo "Installing plugin: $name..."
|
||||
git clone --depth 1 --branch "$branch" "https://github.com/$repo.git" "$dir" 2>/dev/null
|
||||
if [[ $? -eq 0 ]]; then
|
||||
echo "✓ Installed: $name"
|
||||
# Track the repo
|
||||
echo "$repo|$branch" >> "$DF_PLUGIN_REPOS_FILE"
|
||||
else
|
||||
echo "✗ Failed to install: $name"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Source the plugin
|
||||
df_plugin_load "$name"
|
||||
}
|
||||
|
||||
# Load a plugin by name
|
||||
df_plugin_load() {
|
||||
local name="$1"
|
||||
local dir="$DF_PLUGIN_DIR/$name"
|
||||
|
||||
# Check if already loaded
|
||||
[[ " ${DF_LOADED_PLUGINS[*]} " =~ " $name " ]] && return 0
|
||||
|
||||
if [[ -d "$dir" ]]; then
|
||||
# Try common plugin file names
|
||||
local plugin_files=(
|
||||
"$dir/$name.plugin.zsh"
|
||||
"$dir/$name.zsh"
|
||||
"$dir/init.zsh"
|
||||
"$dir/$name.sh"
|
||||
)
|
||||
|
||||
for file in "${plugin_files[@]}"; do
|
||||
if [[ -f "$file" ]]; then
|
||||
source "$file"
|
||||
DF_LOADED_PLUGINS+=("$name")
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Warning: Could not find plugin entry point for $name"
|
||||
return 1
|
||||
else
|
||||
echo "Plugin not found: $name"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Lazy load a plugin (load on first use of command)
|
||||
# Usage: df_plugin_lazy "plugin-name" "command1" "command2"
|
||||
df_plugin_lazy() {
|
||||
local plugin="$1"
|
||||
shift
|
||||
local commands=("$@")
|
||||
|
||||
for cmd in "${commands[@]}"; do
|
||||
eval "
|
||||
$cmd() {
|
||||
unfunction $cmd 2>/dev/null
|
||||
df_plugin_load '$plugin'
|
||||
$cmd \"\$@\"
|
||||
}
|
||||
"
|
||||
done
|
||||
}
|
||||
|
||||
# Update all plugins
|
||||
df_plugin_update() {
|
||||
source "${DOTFILES_DIR:-$HOME/.dotfiles}/zsh/lib/bootstrap.zsh" 2>/dev/null
|
||||
|
||||
df_print_func_name "Plugin Update"
|
||||
echo ""
|
||||
|
||||
for dir in "$DF_PLUGIN_DIR"/*/; do
|
||||
[[ -d "$dir/.git" ]] || continue
|
||||
|
||||
local name=$(basename "$dir")
|
||||
df_print_step "Updating: $name"
|
||||
|
||||
(
|
||||
cd "$dir"
|
||||
git pull --quiet 2>/dev/null && \
|
||||
df_print_success "$name updated" || \
|
||||
df_print_warning "$name: update failed"
|
||||
)
|
||||
done
|
||||
}
|
||||
|
||||
# List installed plugins
|
||||
df_plugin_list() {
|
||||
source "${DOTFILES_DIR:-$HOME/.dotfiles}/zsh/lib/bootstrap.zsh" 2>/dev/null
|
||||
|
||||
df_print_func_name "Installed Plugins"
|
||||
echo ""
|
||||
|
||||
if [[ ! -d "$DF_PLUGIN_DIR" ]] || [[ -z "$(ls -A "$DF_PLUGIN_DIR" 2>/dev/null)" ]]; then
|
||||
df_print_info "No plugins installed"
|
||||
return
|
||||
fi
|
||||
|
||||
for dir in "$DF_PLUGIN_DIR"/*/; do
|
||||
[[ -d "$dir" ]] || continue
|
||||
|
||||
local name=$(basename "$dir")
|
||||
local loaded=""
|
||||
[[ " ${DF_LOADED_PLUGINS[*]} " =~ " $name " ]] && loaded=" ${DF_GREEN}(loaded)${DF_NC}"
|
||||
|
||||
# Get repo info if available
|
||||
local repo_info=""
|
||||
if [[ -d "$dir/.git" ]]; then
|
||||
local remote=$(cd "$dir" && git remote get-url origin 2>/dev/null)
|
||||
repo_info=" ${DF_DIM}${remote##*github.com/}${DF_NC}"
|
||||
fi
|
||||
|
||||
df_print_indent "● ${name}${loaded}${repo_info}"
|
||||
done
|
||||
|
||||
echo ""
|
||||
df_print_section "Loaded Plugins"
|
||||
if [[ ${#DF_LOADED_PLUGINS[@]} -gt 0 ]]; then
|
||||
df_print_indent "${DF_LOADED_PLUGINS[*]}"
|
||||
else
|
||||
df_print_indent "(none)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Remove a plugin
|
||||
df_plugin_remove() {
|
||||
local name="$1"
|
||||
local dir="$DF_PLUGIN_DIR/$name"
|
||||
|
||||
[[ -z "$name" ]] && { echo "Usage: df_plugin_remove <name>"; return 1; }
|
||||
|
||||
if [[ ! -d "$dir" ]]; then
|
||||
echo "Plugin not found: $name"
|
||||
return 1
|
||||
fi
|
||||
|
||||
source "${DOTFILES_DIR:-$HOME/.dotfiles}/zsh/lib/bootstrap.zsh" 2>/dev/null
|
||||
|
||||
df_confirm "Remove plugin '$name'?" || return 1
|
||||
|
||||
rm -rf "$dir"
|
||||
|
||||
# Remove from repos file
|
||||
if [[ -f "$DF_PLUGIN_REPOS_FILE" ]]; then
|
||||
grep -v "/$name|" "$DF_PLUGIN_REPOS_FILE" > "${DF_PLUGIN_REPOS_FILE}.tmp" 2>/dev/null || true
|
||||
mv "${DF_PLUGIN_REPOS_FILE}.tmp" "$DF_PLUGIN_REPOS_FILE"
|
||||
fi
|
||||
|
||||
df_print_success "Removed: $name"
|
||||
df_print_info "Restart shell to fully unload"
|
||||
}
|
||||
|
||||
# Install recommended plugins
|
||||
df_plugin_recommended() {
|
||||
source "${DOTFILES_DIR:-$HOME/.dotfiles}/zsh/lib/bootstrap.zsh" 2>/dev/null
|
||||
|
||||
df_print_func_name "Recommended Plugins"
|
||||
echo ""
|
||||
|
||||
local plugins=(
|
||||
"zsh-users/zsh-autosuggestions:Fish-like autosuggestions"
|
||||
"zsh-users/zsh-syntax-highlighting:Syntax highlighting"
|
||||
"zsh-users/zsh-completions:Additional completions"
|
||||
"romkatv/zsh-defer:Deferred loading for faster startup"
|
||||
"Aloxaf/fzf-tab:FZF-powered tab completion"
|
||||
)
|
||||
|
||||
for plugin_info in "${plugins[@]}"; do
|
||||
local repo="${plugin_info%%:*}"
|
||||
local desc="${plugin_info#*:}"
|
||||
local name="${repo##*/}"
|
||||
local status=""
|
||||
|
||||
if [[ -d "$DF_PLUGIN_DIR/$name" ]]; then
|
||||
status="${DF_GREEN}(installed)${DF_NC}"
|
||||
else
|
||||
status="${DF_DIM}(not installed)${DF_NC}"
|
||||
fi
|
||||
|
||||
echo -e " ${DF_CYAN}$name${DF_NC} $status"
|
||||
echo -e " ${DF_DIM}$desc${DF_NC}"
|
||||
echo -e " ${DF_DIM}Install: df_plugin $repo${DF_NC}"
|
||||
echo ""
|
||||
done
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Command Interface
|
||||
# ============================================================================
|
||||
|
||||
# Main plugin command
|
||||
plugin() {
|
||||
local cmd="${1:-list}"
|
||||
shift 2>/dev/null || true
|
||||
|
||||
case "$cmd" in
|
||||
install|add|i)
|
||||
[[ -z "$1" ]] && { echo "Usage: plugin install <github-user/repo>"; return 1; }
|
||||
df_plugin "$@"
|
||||
;;
|
||||
load|l)
|
||||
df_plugin_load "$@"
|
||||
;;
|
||||
lazy)
|
||||
df_plugin_lazy "$@"
|
||||
;;
|
||||
update|up|u)
|
||||
df_plugin_update
|
||||
;;
|
||||
list|ls)
|
||||
df_plugin_list
|
||||
;;
|
||||
remove|rm|r)
|
||||
df_plugin_remove "$@"
|
||||
;;
|
||||
recommended|rec)
|
||||
df_plugin_recommended
|
||||
;;
|
||||
help|--help|-h)
|
||||
cat << 'EOF'
|
||||
Dotfiles Plugin Manager
|
||||
|
||||
Usage: plugin <command> [args]
|
||||
|
||||
Commands:
|
||||
install <repo> Install plugin from GitHub (e.g., zsh-users/zsh-autosuggestions)
|
||||
load <name> Load an installed plugin
|
||||
lazy <n> <cmds> Lazy-load plugin on command use
|
||||
update Update all plugins
|
||||
list List installed plugins
|
||||
remove <name> Remove a plugin
|
||||
recommended Show recommended plugins
|
||||
|
||||
Examples:
|
||||
plugin install zsh-users/zsh-autosuggestions
|
||||
plugin lazy zsh-nvm nvm node npm
|
||||
plugin update
|
||||
plugin remove zsh-autosuggestions
|
||||
|
||||
EOF
|
||||
;;
|
||||
*)
|
||||
echo "Unknown command: $cmd"
|
||||
echo "Use 'plugin help' for usage"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Initialize
|
||||
# ============================================================================
|
||||
|
||||
# Ensure plugin directory exists
|
||||
[[ ! -d "$DF_PLUGIN_DIR" ]] && mkdir -p "$DF_PLUGIN_DIR"
|
||||
Reference in New Issue
Block a user