Now with more FEATURES (the worth of which who knows, but I like em).

This commit is contained in:
Aaron D. Lee
2025-12-15 16:06:00 -05:00
parent 40d908a7d1
commit 048c9ed8bc
9 changed files with 3177 additions and 0 deletions

View File

@@ -303,6 +303,32 @@ if [[ -f "$HOME/.dotfiles/zsh/functions/snapper.zsh" ]]; then
source "$HOME/.dotfiles/zsh/functions/snapper.zsh"
fi
# --- Smart Command Suggestions ---
if [[ -f "$HOME/.dotfiles/zsh/functions/smart-suggest.zsh" ]]; then
source "$HOME/.dotfiles/zsh/functions/smart-suggest.zsh"
fi
# --- Command Palette (Ctrl+Space or Ctrl+P) ---
if [[ -f "$HOME/.dotfiles/zsh/functions/command-palette.zsh" ]]; then
source "$HOME/.dotfiles/zsh/functions/command-palette.zsh"
fi
# --- Dotfiles Sync Check (on shell start) ---
if [[ "${DOTFILES_AUTO_SYNC_CHECK:-true}" == "true" ]]; then
# Quick async check for dotfiles updates
(dotfiles-sync.sh --auto 2>/dev/null &)
fi
# --- Vault Integration ---
# Source vault secrets into environment (if vault exists and has secrets)
if command -v vault.sh &>/dev/null && [[ -f "$HOME/.dotfiles/vault/secrets.enc" ]]; then
eval "$(vault.sh shell 2>/dev/null)" || true
fi
# --- Local Configuration ---
[ -f ~/.zshrc.local ] && source ~/.zshrc.local

View File

@@ -0,0 +1,310 @@
# ============================================================================
# Command Palette - Fuzzy Command Launcher for Zsh
# ============================================================================
# A Raycast/Alfred-style command palette for the terminal
#
# Features:
# - Search aliases, functions, recent commands
# - Search bookmarked directories
# - Search dotfiles scripts
# - Quick actions (edit config, reload shell, etc.)
#
# Keybinding: Ctrl+Space (configurable)
#
# Requirements: fzf
#
# Add to .zshrc:
# source ~/.dotfiles/zsh/functions/command-palette.zsh
# ============================================================================
# ============================================================================
# Configuration
# ============================================================================
typeset -g PALETTE_HOTKEY="${PALETTE_HOTKEY:-^@}" # Ctrl+Space
typeset -g PALETTE_HISTORY_SIZE=50
typeset -g PALETTE_BOOKMARKS_FILE="$HOME/.dotfiles/.bookmarks"
typeset -g DOTFILES_DIR="${DOTFILES_DIR:-$HOME/.dotfiles}"
# Icons (works with most terminals)
typeset -g ICON_ALIAS="⚡"
typeset -g ICON_FUNC="λ"
typeset -g ICON_HIST="↺"
typeset -g ICON_DIR="📁"
typeset -g ICON_SCRIPT="⚙"
typeset -g ICON_ACTION="★"
typeset -g ICON_GIT="⎇"
typeset -g ICON_DOCKER="◉"
typeset -g ICON_EDIT="✎"
typeset -g ICON_RUN="▶"
# ============================================================================
# Check Dependencies
# ============================================================================
_palette_check_deps() {
if ! command -v fzf &>/dev/null; then
echo "Command palette requires fzf."
echo "Install: git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf && ~/.fzf/install"
return 1
fi
return 0
}
# ============================================================================
# Data Sources
# ============================================================================
_palette_get_aliases() {
alias | sed 's/^alias //' | while IFS='=' read -r name cmd; do
cmd="${cmd#\'}"
cmd="${cmd%\'}"
cmd="${cmd#\"}"
cmd="${cmd%\"}"
printf "%s\t%s\t%s\t%s\n" "$ICON_ALIAS" "alias" "$name" "$cmd"
done
}
_palette_get_functions() {
# Get user-defined functions (not starting with _)
print -l ${(ok)functions} | grep -v '^_' | while read -r name; do
printf "%s\t%s\t%s\t%s\n" "$ICON_FUNC" "func" "$name" "function"
done
}
_palette_get_history() {
fc -ln -$PALETTE_HISTORY_SIZE | tac | awk '!seen[$0]++' | head -30 | while read -r cmd; do
[[ -n "$cmd" ]] && printf "%s\t%s\t%s\t%s\n" "$ICON_HIST" "history" "${cmd:0:50}" "$cmd"
done
}
_palette_get_bookmarks() {
[[ ! -f "$PALETTE_BOOKMARKS_FILE" ]] && return
while IFS='|' read -r name path; do
[[ -n "$name" && -n "$path" ]] && printf "%s\t%s\t%s\t%s\n" "$ICON_DIR" "bookmark" "$name" "cd $path"
done < "$PALETTE_BOOKMARKS_FILE"
}
_palette_get_scripts() {
[[ ! -d "$DOTFILES_DIR/bin" ]] && return
for script in "$DOTFILES_DIR/bin"/*.sh; do
[[ -f "$script" ]] || continue
local name=$(basename "$script" .sh)
printf "%s\t%s\t%s\t%s\n" "$ICON_SCRIPT" "script" "$name" "$script"
done
}
_palette_get_git_commands() {
# Only show if in git repo
git rev-parse --git-dir &>/dev/null || return
local branch=$(git branch --show-current 2>/dev/null)
printf "%s\t%s\t%s\t%s\n" "$ICON_GIT" "git" "status" "git status"
printf "%s\t%s\t%s\t%s\n" "$ICON_GIT" "git" "pull $branch" "git pull origin $branch"
printf "%s\t%s\t%s\t%s\n" "$ICON_GIT" "git" "push $branch" "git push origin $branch"
printf "%s\t%s\t%s\t%s\n" "$ICON_GIT" "git" "diff" "git diff"
printf "%s\t%s\t%s\t%s\n" "$ICON_GIT" "git" "log" "git log --oneline -20"
printf "%s\t%s\t%s\t%s\n" "$ICON_GIT" "git" "stash" "git stash"
printf "%s\t%s\t%s\t%s\n" "$ICON_GIT" "git" "stash pop" "git stash pop"
}
_palette_get_docker_commands() {
command -v docker &>/dev/null || return
printf "%s\t%s\t%s\t%s\n" "$ICON_DOCKER" "docker" "ps" "docker ps"
printf "%s\t%s\t%s\t%s\n" "$ICON_DOCKER" "docker" "ps -a" "docker ps -a"
printf "%s\t%s\t%s\t%s\n" "$ICON_DOCKER" "docker" "images" "docker images"
printf "%s\t%s\t%s\t%s\n" "$ICON_DOCKER" "docker" "compose up" "docker-compose up -d"
printf "%s\t%s\t%s\t%s\n" "$ICON_DOCKER" "docker" "compose down" "docker-compose down"
printf "%s\t%s\t%s\t%s\n" "$ICON_DOCKER" "docker" "prune" "docker system prune -af"
}
_palette_get_actions() {
printf "%s\t%s\t%s\t%s\n" "$ICON_ACTION" "action" "Reload shell" "exec zsh"
printf "%s\t%s\t%s\t%s\n" "$ICON_EDIT" "action" "Edit .zshrc" "${EDITOR:-vim} ~/.zshrc"
printf "%s\t%s\t%s\t%s\n" "$ICON_EDIT" "action" "Edit dotfiles.conf" "${EDITOR:-vim} $DOTFILES_DIR/dotfiles.conf"
printf "%s\t%s\t%s\t%s\n" "$ICON_EDIT" "action" "Edit theme" "${EDITOR:-vim} $DOTFILES_DIR/zsh/themes/adlee.zsh-theme"
printf "%s\t%s\t%s\t%s\n" "$ICON_SCRIPT" "action" "Dotfiles doctor" "dotfiles-doctor.sh"
printf "%s\t%s\t%s\t%s\n" "$ICON_SCRIPT" "action" "Dotfiles sync" "dotfiles-sync.sh"
printf "%s\t%s\t%s\t%s\n" "$ICON_SCRIPT" "action" "Shell stats" "shell-stats.sh"
printf "%s\t%s\t%s\t%s\n" "$ICON_SCRIPT" "action" "Vault list" "vault.sh list"
printf "%s\t%s\t%s\t%s\n" "$ICON_ACTION" "action" "Clear screen" "clear"
printf "%s\t%s\t%s\t%s\n" "$ICON_DIR" "action" "Home" "cd ~"
printf "%s\t%s\t%s\t%s\n" "$ICON_DIR" "action" "Dotfiles" "cd $DOTFILES_DIR"
printf "%s\t%s\t%s\t%s\n" "$ICON_DIR" "action" "Projects" "cd ~/projects 2>/dev/null || cd ~"
}
_palette_get_directories() {
# Recent directories from dirstack
dirs -v 2>/dev/null | tail -n +2 | head -10 | while read -r num dir; do
[[ -n "$dir" ]] && printf "%s\t%s\t%s\t%s\n" "$ICON_DIR" "recent" "$dir" "cd $dir"
done
}
# ============================================================================
# Main Palette Function
# ============================================================================
_palette_generate_entries() {
_palette_get_actions
_palette_get_git_commands
_palette_get_docker_commands
_palette_get_aliases
_palette_get_bookmarks
_palette_get_scripts
_palette_get_directories
_palette_get_history
_palette_get_functions
}
command_palette() {
_palette_check_deps || return 1
local selection
selection=$(_palette_generate_entries | \
fzf --height=60% \
--layout=reverse \
--border=rounded \
--prompt=' ' \
--pointer='▶' \
--header='Command Palette (ESC to cancel)' \
--preview-window=hidden \
--delimiter=$'\t' \
--with-nth=1,3 \
--tabstop=2 \
--ansi \
--bind='ctrl-r:reload(_palette_generate_entries)' \
--expect=ctrl-e,ctrl-y)
[[ -z "$selection" ]] && return
local key=$(echo "$selection" | head -1)
local line=$(echo "$selection" | tail -1)
local cmd=$(echo "$line" | cut -f4)
[[ -z "$cmd" ]] && return
case "$key" in
ctrl-e)
# Edit mode - put command on line without executing
print -z "$cmd"
;;
ctrl-y)
# Yank - copy to clipboard
echo -n "$cmd" | pbcopy 2>/dev/null || echo -n "$cmd" | xclip -selection clipboard 2>/dev/null
echo "Copied: $cmd"
;;
*)
# Default - execute
echo " $cmd"
eval "$cmd"
;;
esac
}
# Alias for easier access
palette() { command_palette; }
p() { command_palette; }
# ============================================================================
# Bookmark Management
# ============================================================================
bookmark() {
local name="$1"
local path="${2:-$(pwd)}"
if [[ -z "$name" ]]; then
echo "Usage: bookmark <name> [path]"
echo " bookmark list"
echo " bookmark delete <name>"
return 1
fi
case "$name" in
list|ls)
if [[ -f "$PALETTE_BOOKMARKS_FILE" ]]; then
echo "Bookmarks:"
while IFS='|' read -r n p; do
echo " $n$p"
done < "$PALETTE_BOOKMARKS_FILE"
else
echo "No bookmarks yet"
fi
;;
delete|rm)
local to_delete="$2"
[[ -z "$to_delete" ]] && { echo "Specify bookmark to delete"; return 1; }
[[ -f "$PALETTE_BOOKMARKS_FILE" ]] && {
grep -v "^$to_delete|" "$PALETTE_BOOKMARKS_FILE" > "${PALETTE_BOOKMARKS_FILE}.tmp"
mv "${PALETTE_BOOKMARKS_FILE}.tmp" "$PALETTE_BOOKMARKS_FILE"
echo "Deleted: $to_delete"
}
;;
*)
mkdir -p "$(dirname "$PALETTE_BOOKMARKS_FILE")"
# Remove existing bookmark with same name
[[ -f "$PALETTE_BOOKMARKS_FILE" ]] && {
grep -v "^$name|" "$PALETTE_BOOKMARKS_FILE" > "${PALETTE_BOOKMARKS_FILE}.tmp"
mv "${PALETTE_BOOKMARKS_FILE}.tmp" "$PALETTE_BOOKMARKS_FILE"
}
echo "$name|$path" >> "$PALETTE_BOOKMARKS_FILE"
echo "Bookmarked: $name$path"
;;
esac
}
# Quick jump to bookmark
jump() {
local name="$1"
if [[ -z "$name" ]]; then
# Fuzzy select bookmark
[[ ! -f "$PALETTE_BOOKMARKS_FILE" ]] && { echo "No bookmarks"; return 1; }
local selection=$(cat "$PALETTE_BOOKMARKS_FILE" | \
fzf --height=40% --layout=reverse --delimiter='|' --with-nth=1 \
--preview='echo "Path: $(echo {} | cut -d"|" -f2)"')
[[ -n "$selection" ]] && {
local path=$(echo "$selection" | cut -d'|' -f2)
cd "$path" && echo "$path"
}
else
# Direct jump
local path=$(grep "^$name|" "$PALETTE_BOOKMARKS_FILE" 2>/dev/null | cut -d'|' -f2)
[[ -n "$path" ]] && cd "$path" || echo "Bookmark not found: $name"
fi
}
# Aliases
bm() { bookmark "$@"; }
j() { jump "$@"; }
# ============================================================================
# Widget for Keybinding
# ============================================================================
_palette_widget() {
command_palette
zle reset-prompt
}
# Register widget
zle -N _palette_widget
# Bind to Ctrl+Space (^@)
bindkey "$PALETTE_HOTKEY" _palette_widget
# Alternative binding: Ctrl+P
bindkey '^P' _palette_widget
# ============================================================================
# Initialization Message
# ============================================================================
# Uncomment to show on load:
# echo "Command palette loaded. Press Ctrl+Space or Ctrl+P to open."

View File

@@ -0,0 +1,446 @@
# ============================================================================
# Smart Command Suggestions for Zsh
# ============================================================================
# Provides intelligent suggestions when commands fail or could be improved
#
# Features:
# - Typo correction for common commands
# - Suggests existing aliases for frequently typed commands
# - "Did you mean?" for unknown commands
# - Package installation suggestions for missing commands
#
# Add to .zshrc:
# source ~/.dotfiles/zsh/functions/smart-suggest.zsh
# ============================================================================
# ============================================================================
# Configuration
# ============================================================================
# Enable/disable features
typeset -g SMART_SUGGEST_ENABLED=true
typeset -g SMART_SUGGEST_TYPOS=true
typeset -g SMART_SUGGEST_ALIASES=true
typeset -g SMART_SUGGEST_PACKAGES=true
typeset -g SMART_SUGGEST_HISTORY=true
# Tracking file for alias suggestions
typeset -g SMART_SUGGEST_TRACK_FILE="$HOME/.cache/smart-suggest-track"
# Colors
typeset -g SS_CYAN=$'\033[0;36m'
typeset -g SS_YELLOW=$'\033[1;33m'
typeset -g SS_GREEN=$'\033[0;32m'
typeset -g SS_RED=$'\033[0;31m'
typeset -g SS_DIM=$'\033[2m'
typeset -g SS_NC=$'\033[0m'
# ============================================================================
# Common Typo Database
# ============================================================================
typeset -gA TYPO_CORRECTIONS=(
# Git typos
[gti]="git"
[gitt]="git"
[got]="git"
[gut]="git"
[gi]="git"
[giit]="git"
[ggit]="git"
[gitst]="git st"
[gits]="git s"
[gitl]="git l"
[gitd]="git d"
[gitp]="git p"
[psuh]="push"
[psull]="pull"
[pul]="pull"
[puhs]="push"
[stauts]="status"
[statis]="status"
[statuus]="status"
[comit]="commit"
[commti]="commit"
[commt]="commit"
[chekcout]="checkout"
[chekout]="checkout"
[checkou]="checkout"
[branhc]="branch"
[barnch]="branch"
[bracnh]="branch"
[marge]="merge"
[merg]="merge"
[stsh]="stash"
[stahs]="stash"
# Docker typos
[dokcer]="docker"
[doker]="docker"
[docekr]="docker"
[dcoker]="docker"
[dockr]="docker"
[docke]="docker"
[docker-compoes]="docker-compose"
[docker-compsoe]="docker-compose"
[dokcer-compose]="docker-compose"
# Common command typos
[sl]="ls"
[l]="ls"
[sls]="ls"
[lss]="ls"
[cta]="cat"
[catt]="cat"
[caat]="cat"
[grpe]="grep"
[gerp]="grep"
[gre]="grep"
[grepp]="grep"
[mkdri]="mkdir"
[mkdr]="mkdir"
[mdkir]="mkdir"
[mdir]="mkdir"
[rn]="rm"
[rmm]="rm"
[chmdo]="chmod"
[chomd]="chmod"
[chonw]="chown"
[cown]="chown"
[tarr]="tar"
[tart]="tar"
[wegt]="wget"
[wgte]="wget"
[weget]="wget"
[crul]="curl"
[crul]="curl"
[curll]="curl"
[pytohn]="python"
[pyhton]="python"
[pythn]="python"
[pyton]="python"
[pthon]="python"
[pytho]="python"
[ndoe]="node"
[noed]="node"
[noode]="node"
[npn]="npm"
[nmpm]="npm"
[nppm]="npm"
[yran]="yarn"
[yaarn]="yarn"
[yanr]="yarn"
[suod]="sudo"
[sudi]="sudo"
[sduo]="sudo"
[sudoo]="sudo"
[sssh]="ssh"
[shh]="ssh"
[sssh]="ssh"
[scpp]="scp"
[spcp]="scp"
[vmi]="vim"
[imv]="vim"
[viim]="vim"
[cde]="code"
[cdoe]="code"
[cod]="code"
[clera]="clear"
[cler]="clear"
[claer]="clear"
[ecoh]="echo"
[ehco]="echo"
[echoo]="echo"
[exti]="exit"
[ext]="exit"
[exitt]="exit"
[eixt]="exit"
[histroy]="history"
[hisotry]="history"
[hsitory]="history"
[histrory]="history"
[maek]="make"
[mkae]="make"
[amke]="make"
[makee]="make"
[ccd]="cd"
[cdd]="cd"
[ccd]="cd"
)
# ============================================================================
# Package Manager Detection
# ============================================================================
_ss_get_package_manager() {
if command -v apt-get &>/dev/null; then
echo "apt"
elif command -v dnf &>/dev/null; then
echo "dnf"
elif command -v pacman &>/dev/null; then
echo "pacman"
elif command -v brew &>/dev/null; then
echo "brew"
else
echo ""
fi
}
# Common commands and their packages
typeset -gA COMMAND_PACKAGES=(
[htop]="htop"
[tree]="tree"
[jq]="jq"
[fd]="fd-find:apt fd:pacman fd:brew"
[rg]="ripgrep"
[bat]="bat"
[eza]="eza"
[exa]="exa"
[fzf]="fzf"
[tldr]="tldr"
[ncdu]="ncdu"
[duf]="duf"
[dust]="dust"
[procs]="procs"
[bottom]="bottom"
[btm]="bottom"
[lazygit]="lazygit"
[lazydocker]="lazydocker"
[neofetch]="neofetch"
[fastfetch]="fastfetch"
[httpie]="httpie"
[http]="httpie"
[delta]="git-delta:apt delta:pacman git-delta:brew"
[glow]="glow"
[navi]="navi"
)
_ss_suggest_package() {
local cmd="$1"
local pm=$(_ss_get_package_manager)
[[ -z "$pm" ]] && return 1
local pkg_info="${COMMAND_PACKAGES[$cmd]}"
[[ -z "$pkg_info" ]] && return 1
local pkg=""
# Check for PM-specific package name
if [[ "$pkg_info" == *":"* ]]; then
# Format: "pkg1:pm1 pkg2:pm2"
for entry in ${(s: :)pkg_info}; do
local p="${entry%%:*}"
local m="${entry##*:}"
if [[ "$m" == "$pm" ]]; then
pkg="$p"
break
fi
done
# Fallback to first package
[[ -z "$pkg" ]] && pkg="${${(s: :)pkg_info}[1]%%:*}"
else
pkg="$pkg_info"
fi
[[ -z "$pkg" ]] && return 1
local install_cmd=""
case "$pm" in
apt) install_cmd="sudo apt install $pkg" ;;
dnf) install_cmd="sudo dnf install $pkg" ;;
pacman) install_cmd="sudo pacman -S $pkg" ;;
brew) install_cmd="brew install $pkg" ;;
esac
echo "$install_cmd"
}
# ============================================================================
# Alias Tracking
# ============================================================================
_ss_track_command() {
[[ "$SMART_SUGGEST_ALIASES" != true ]] && return
local cmd="$1"
[[ ${#cmd} -lt 8 ]] && return # Skip short commands
mkdir -p "$(dirname "$SMART_SUGGEST_TRACK_FILE")"
echo "$cmd" >> "$SMART_SUGGEST_TRACK_FILE"
# Periodically check for alias suggestions
local count=$(grep -Fc "$cmd" "$SMART_SUGGEST_TRACK_FILE" 2>/dev/null || echo 0)
if [[ $count -ge 10 && $((count % 10)) -eq 0 ]]; then
_ss_suggest_alias_for "$cmd" "$count"
fi
}
_ss_suggest_alias_for() {
local cmd="$1"
local count="$2"
# Check if an alias already exists for this command
local existing=$(alias | grep -F "='$cmd'" | head -1 | cut -d= -f1)
if [[ -n "$existing" ]]; then
echo
echo -e "${SS_CYAN}💡 Tip:${SS_NC} You've typed '${SS_YELLOW}$cmd${SS_NC}' $count times"
echo -e " You already have an alias: ${SS_GREEN}$existing${SS_NC}"
else
# Generate suggested alias name
local suggested=$(echo "$cmd" | awk '{
for(i=1; i<=NF && i<=3; i++)
printf substr($i,1,1)
}')
echo
echo -e "${SS_CYAN}💡 Tip:${SS_NC} You've typed '${SS_YELLOW}$cmd${SS_NC}' $count times"
echo -e " Consider adding: ${SS_GREEN}alias $suggested='$cmd'${SS_NC}"
fi
}
# ============================================================================
# Command Not Found Handler
# ============================================================================
command_not_found_handler() {
local cmd="$1"
shift
local args="$@"
[[ "$SMART_SUGGEST_ENABLED" != true ]] && {
echo "zsh: command not found: $cmd"
return 127
}
echo -e "${SS_RED}${SS_NC} Command not found: ${SS_YELLOW}$cmd${SS_NC}"
local suggestion_made=false
# Check for typo
if [[ "$SMART_SUGGEST_TYPOS" == true ]]; then
local correction="${TYPO_CORRECTIONS[$cmd]}"
if [[ -n "$correction" ]]; then
echo -e "${SS_CYAN}${SS_NC} Did you mean: ${SS_GREEN}$correction${SS_NC}?"
echo -e " ${SS_DIM}Run: $correction $args${SS_NC}"
suggestion_made=true
fi
fi
# Check for similar commands
if [[ "$suggestion_made" != true ]]; then
local similar=$(compgen -c 2>/dev/null | grep -i "^${cmd:0:3}" | head -3 | tr '\n' ', ' | sed 's/,$//')
if [[ -n "$similar" ]]; then
echo -e "${SS_CYAN}${SS_NC} Similar commands: ${SS_GREEN}$similar${SS_NC}"
suggestion_made=true
fi
fi
# Suggest package installation
if [[ "$SMART_SUGGEST_PACKAGES" == true ]]; then
local install_cmd=$(_ss_suggest_package "$cmd")
if [[ -n "$install_cmd" ]]; then
echo -e "${SS_CYAN}${SS_NC} To install: ${SS_GREEN}$install_cmd${SS_NC}"
suggestion_made=true
fi
fi
return 127
}
# ============================================================================
# Pre-exec Hook for Tracking
# ============================================================================
_ss_preexec_hook() {
local cmd="$1"
# Extract just the command (first word)
local first_word="${cmd%% *}"
# Track full commands for alias suggestions
_ss_track_command "$cmd"
}
# ============================================================================
# Post-command Hook for Suggestions
# ============================================================================
_ss_precmd_hook() {
local exit_code=$?
# Only suggest if last command failed
[[ $exit_code -eq 0 ]] && return
# Get last command
local last_cmd=$(fc -ln -1 2>/dev/null | sed 's/^[[:space:]]*//')
[[ -z "$last_cmd" ]] && return
local first_word="${last_cmd%% *}"
# Check if it's a git command with typo
if [[ "$first_word" == "git" && $exit_code -ne 0 ]]; then
local git_subcmd=$(echo "$last_cmd" | awk '{print $2}')
local correction="${TYPO_CORRECTIONS[$git_subcmd]}"
if [[ -n "$correction" ]]; then
echo -e "${SS_CYAN}${SS_NC} Did you mean: ${SS_GREEN}git $correction${SS_NC}?"
fi
fi
}
# ============================================================================
# Quick Fix Function
# ============================================================================
# Run the suggested correction
# Usage: !! <correction> or just press up and edit
fuck() {
local last_cmd=$(fc -ln -1 2>/dev/null | sed 's/^[[:space:]]*//')
local first_word="${last_cmd%% *}"
# Check for typo correction
local correction="${TYPO_CORRECTIONS[$first_word]}"
if [[ -n "$correction" ]]; then
local fixed_cmd="${last_cmd/$first_word/$correction}"
echo -e "${SS_GREEN}Running:${SS_NC} $fixed_cmd"
eval "$fixed_cmd"
else
echo "No automatic fix available"
echo "Last command: $last_cmd"
fi
}
# ============================================================================
# Setup Hooks
# ============================================================================
_ss_setup() {
# Add preexec hook
autoload -Uz add-zsh-hook
add-zsh-hook preexec _ss_preexec_hook
add-zsh-hook precmd _ss_precmd_hook
}
# Initialize
[[ "$SMART_SUGGEST_ENABLED" == true ]] && _ss_setup
# ============================================================================
# Usage Examples (commented)
# ============================================================================
# $ gti status
# ✗ Command not found: gti
# → Did you mean: git?
# Run: git status
# $ dokcer ps
# ✗ Command not found: dokcer
# → Did you mean: docker?
# After typing "docker-compose up -d" 10 times:
# 💡 Tip: You've typed 'docker-compose up -d' 10 times
# Consider adding: alias dcu='docker-compose up -d'

338
zsh/zshrc Normal file
View File

@@ -0,0 +1,338 @@
# ============================================================================
# ADLee's ZSH Configuration
# ============================================================================
# Path to oh-my-zsh installation
export ZSH="$HOME/.oh-my-zsh"
# ============================================================================
# Theme Configuration
# ============================================================================
ZSH_THEME="adlee"
# ============================================================================
# Oh-My-Zsh Settings
# ============================================================================
# Update behavior
zstyle ':omz:update' mode reminder
zstyle ':omz:update' frequency 13
# Display red dots whilst waiting for completion
COMPLETION_WAITING_DOTS="true"
# History timestamp format
HIST_STAMPS="yyyy-mm-dd"
# ============================================================================
# Plugins
# ============================================================================
plugins=(
git
docker
docker-compose
kubectl
sudo
fzf
zsh-autosuggestions
zsh-syntax-highlighting
)
# Note: Install additional plugins with:
# git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
# git clone https://github.com/zsh-users/zsh-syntax-highlighting ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
# ============================================================================
# Load Oh-My-Zsh
# ============================================================================
source $ZSH/oh-my-zsh.sh
# ============================================================================
# User Configuration
# ============================================================================
# --- Environment Variables ---
export EDITOR='vim'
export VISUAL='vim'
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
export PATH="$HOME/.local/bin:$PATH"
# --- Aliases ---
# Navigation
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'
alias ~='cd ~'
# List files
if command -v eza &> /dev/null; then
alias ls='eza --icons'
alias ll='eza -lah --icons'
alias la='eza -a --icons'
alias lt='eza --tree --level=2 --icons'
else
alias ll='ls -lah'
alias la='ls -A'
fi
# Cat with syntax highlighting
if command -v batcat &> /dev/null; then
alias cat='batcat --paging=never'
alias bat='batcat'
elif command -v bat &> /dev/null; then
alias cat='bat --paging=never'
fi
# Git shortcuts
alias g='git'
alias gs='git status'
alias ga='git add'
alias gc='git commit'
alias gp='git push'
alias gl='git pull'
alias gd='git diff'
alias gco='git checkout'
alias gb='git branch'
alias glog='git log --oneline --graph --decorate --all'
# Docker shortcuts
alias d='docker'
alias dc='docker-compose'
alias dps='docker ps'
alias dpa='docker ps -a'
alias di='docker images'
alias dex='docker exec -it'
# System shortcuts
alias reload='source ~/.zshrc'
alias zshconfig='vim ~/.zshrc'
alias themeconfig='vim ~/.oh-my-zsh/themes/adlee.zsh-theme'
alias h='history'
alias c='clear'
# Safe operations
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
# Network
alias myip='curl ifconfig.me'
alias ports='netstat -tulanp'
# --- Functions ---
# Juuuust puuush it.
push-it() {
git add .
git commit -m "$1"
git push origin
}
# Create directory and cd into it
mkcd() {
mkdir -p "$1" && cd "$1"
}
# Extract various archive formats
extract() {
if [[ -f "$1" ]]; then
case "$1" in
*.tar.bz2) tar xjf "$1" ;;
*.tar.gz) tar xzf "$1" ;;
*.bz2) bunzip2 "$1" ;;
*.rar) unrar x "$1" ;;
*.gz) gunzip "$1" ;;
*.tar) tar xf "$1" ;;
*.tbz2) tar xjf "$1" ;;
*.tgz) tar xzf "$1" ;;
*.zip) unzip "$1" ;;
*.Z) uncompress "$1" ;;
*.7z) 7z x "$1" ;;
*) echo "'$1' cannot be extracted via extract()" ;;
esac
else
echo "'$1' is not a valid file"
fi
}
# Quick find file
ff() {
find . -type f -iname "*$1*"
}
# Quick find directory (renamed to avoid conflict with fd tool)
fdir() {
find . -type d -iname "*$1*"
}
# Quick backup
backup() {
cp "$1" "$1.backup-$(date +%Y%m%d-%H%M%S)"
}
# --- FZF Configuration ---
if command -v fzf &> /dev/null; then
if command -v fd &> /dev/null; then
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
fi
export FZF_DEFAULT_OPTS='--height 40% --layout=reverse --border'
bindkey '^R' fzf-history-widget
fi
# --- History Configuration ---
HISTSIZE=10000
SAVEHIST=10000
HISTFILE=~/.zsh_history
setopt SHARE_HISTORY
setopt APPEND_HISTORY
setopt EXTENDED_HISTORY
setopt HIST_IGNORE_ALL_DUPS
setopt HIST_FIND_NO_DUPS
setopt HIST_IGNORE_SPACE
# --- Key Bindings ---
bindkey "^[[1;5C" forward-word # Ctrl+Right
bindkey "^[[1;5D" backward-word # Ctrl+Left
bindkey "^[[H" beginning-of-line # Home
bindkey "^[[F" end-of-line # End
bindkey "^[[3~" delete-char # Delete
# --- Custom Widgets ---
# Alt+R to reload zsh config
reload-zsh() {
source ~/.zshrc
echo "✓ zsh configuration reloaded"
zle reset-prompt
}
zle -N reload-zsh
bindkey "^[r" reload-zsh
# Alt+G to show git status
git-status-widget() {
echo
git status
zle reset-prompt
}
zle -N git-status-widget
bindkey "^[g" git-status-widget
# ============================================================================
# Lazy-loaded Tools (for faster shell startup)
# ============================================================================
# --- NVM (lazy load) ---
# Only loads when you first use node, npm, nvm, or npx
export NVM_DIR="$HOME/.nvm"
_load_nvm() {
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
}
# Create lazy-load wrappers
if [ -s "$NVM_DIR/nvm.sh" ]; then
nvm() {
unfunction nvm node npm npx 2>/dev/null
_load_nvm
nvm "$@"
}
node() {
unfunction nvm node npm npx 2>/dev/null
_load_nvm
node "$@"
}
npm() {
unfunction nvm node npm npx 2>/dev/null
_load_nvm
npm "$@"
}
npx() {
unfunction nvm node npm npx 2>/dev/null
_load_nvm
npx "$@"
}
fi
# --- Python virtualenvwrapper (lazy load) ---
export WORKON_HOME=$HOME/.virtualenvs
_load_virtualenvwrapper() {
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
[ -f /usr/local/bin/virtualenvwrapper.sh ] && source /usr/local/bin/virtualenvwrapper.sh
}
if [ -f /usr/local/bin/virtualenvwrapper.sh ]; then
workon() {
unfunction workon mkvirtualenv rmvirtualenv 2>/dev/null
_load_virtualenvwrapper
workon "$@"
}
mkvirtualenv() {
unfunction workon mkvirtualenv rmvirtualenv 2>/dev/null
_load_virtualenvwrapper
mkvirtualenv "$@"
}
fi
# --- Rust cargo (only if exists) ---
[ -f "$HOME/.cargo/env" ] && source "$HOME/.cargo/env"
# --- OS-Specific Configuration ---
case "$(uname -s)" in
Darwin*)
export HOMEBREW_NO_ANALYTICS=1
;;
esac
# --- Snapper Functions ---
if [[ -f "$HOME/.dotfiles/zsh/functions/snapper.zsh" ]]; then
source "$HOME/.dotfiles/zsh/functions/snapper.zsh"
fi
# --- Smart Command Suggestions ---
if [[ -f "$HOME/.dotfiles/zsh/functions/smart-suggest.zsh" ]]; then
source "$HOME/.dotfiles/zsh/functions/smart-suggest.zsh"
fi
# --- Command Palette (Ctrl+Space or Ctrl+P) ---
if [[ -f "$HOME/.dotfiles/zsh/functions/command-palette.zsh" ]]; then
source "$HOME/.dotfiles/zsh/functions/command-palette.zsh"
fi
# --- Dotfiles Sync Check (on shell start) ---
if [[ "${DOTFILES_AUTO_SYNC_CHECK:-true}" == "true" ]]; then
# Quick async check for dotfiles updates
(dotfiles-sync.sh --auto 2>/dev/null &)
fi
# --- Vault Integration ---
# Source vault secrets into environment (if vault exists and has secrets)
if command -v vault.sh &>/dev/null && [[ -f "$HOME/.dotfiles/vault/secrets.enc" ]]; then
eval "$(vault.sh shell 2>/dev/null)" || true
fi
# --- Local Configuration ---
[ -f ~/.zshrc.local ] && source ~/.zshrc.local
# ============================================================================
# End of Configuration
# ============================================================================