# ==============================================================================
# .zshrc - Zsh 配置文件
# 环境: macOS (Intel/Apple Silicon) + Ghostty + Zsh
# 最后更新: 2026-04-05
# ==============================================================================
# 性能分析工具(调试时取消注释)
# zmodload zsh/zprof
# ------------------------------------------------------------------------------
# 1. 基础环境变量
# ------------------------------------------------------------------------------
# [优化] 用 brew --prefix 检测是目前最可靠的方式,避免路径硬编码失效。
# 但 brew 命令本身有启动开销,因此先尝试常见路径快速判断,仅在失败时 fallback。
if [[ -x /opt/homebrew/bin/brew ]]; then
export HOMEBREW_PREFIX="/opt/homebrew" # Apple Silicon
elif [[ -x /usr/local/bin/brew ]]; then
export HOMEBREW_PREFIX="/usr/local" # Intel Mac
else
export HOMEBREW_PREFIX="$(brew --prefix 2>/dev/null || echo /usr/local)"
fi
export EDITOR='code'
export VISUAL='code'
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
export COLORTERM=truecolor
# 包管理器 home(集中声明,后续 PATH 引用)
export PNPM_HOME="$HOME/Library/pnpm"
export BUN_INSTALL="$HOME/.bun"
export SDKMAN_DIR="$HOME/.sdkman"
# ------------------------------------------------------------------------------
# 2. PATH 配置(集中管理,避免分散追加)
# ------------------------------------------------------------------------------
# [修复] 原文件末尾有 antigravity / bun / codemaker 三处零散 PATH 追加,
# 已统一移入此处。typeset -U 自动去重,防止 PATH 膨胀。
typeset -U path
path=(
"$HOME/.local/bin"
"$HOME/bin"
"$HOME/.antigravity/antigravity/bin" # Antigravity
"$HOME/.codemaker/bin" # CodeMaker
"$BUN_INSTALL/bin" # Bun
"$PNPM_HOME" # pnpm 全局包
"$HOMEBREW_PREFIX/bin"
"$HOMEBREW_PREFIX/sbin"
$path
)
export PATH
# ------------------------------------------------------------------------------
# 3. 补全系统
# ------------------------------------------------------------------------------
if [[ -d "$HOMEBREW_PREFIX/share/zsh/site-functions" ]]; then
FPATH="$HOMEBREW_PREFIX/share/zsh/site-functions:$FPATH"
fi
autoload -Uz compinit
# [说明] (N) = 空值安全; .mh+24 = 文件修改时间超过 24 小时
# 超过 24h 才重新生成缓存,其余时间用 -C 跳过安全检查加速启动
local zcompdump="$HOME/.zcompdump"
if [[ ! -f "$zcompdump" ]] || [[ -n "$zcompdump"(#qnmh24-|qN.mh+24) ]]; then
compinit
else
compinit -C
fi
zstyle ':completion:*' menu select
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
zstyle ':completion:*:descriptions' format '%B%d%b'
zstyle ':completion:*:warnings' format 'No matches for: %d'
# ------------------------------------------------------------------------------
# 4. 历史记录
# ------------------------------------------------------------------------------
HISTFILE=~/.zsh_history
HISTSIZE=50000
SAVEHIST=50000
setopt HIST_IGNORE_DUPS
setopt HIST_IGNORE_SPACE
setopt HIST_REDUCE_BLANKS
setopt SHARE_HISTORY
setopt EXTENDED_HISTORY
setopt HIST_VERIFY
# ------------------------------------------------------------------------------
# 5. Shell 选项
# ------------------------------------------------------------------------------
setopt AUTO_CD
setopt AUTO_PUSHD
setopt PUSHD_IGNORE_DUPS
setopt CORRECT
setopt INTERACTIVE_COMMENTS
setopt GLOB_DOTS
# [删除] NO_BEEP 在现代 macOS 上由系统设置控制,此处无效,已移除。
# ------------------------------------------------------------------------------
# 6. SSH Agent(异步启动,不阻塞 shell 加载)
# ------------------------------------------------------------------------------
# [优化] 改为后台异步执行(&!),避免 keychain 访问阻塞启动。
# 权衡:极少情况下首次 git push 时 agent 可能还未就绪,重试一次即可。
ssh_agent_start() {
local ssh_env_file="${XDG_RUNTIME_DIR:-$HOME/.cache}/ssh-agent.env"
ssh-add -l >/dev/null 2>&1
local agent_status=$?
if [[ $agent_status -eq 0 ]]; then
return 0
fi
if [[ $agent_status -eq 2 ]]; then
if [[ -f "$ssh_env_file" ]]; then
source "$ssh_env_file" >/dev/null
ssh-add -l >/dev/null 2>&1
agent_status=$?
fi
if [[ $agent_status -eq 2 ]]; then
mkdir -p "$(dirname "$ssh_env_file")"
ssh-agent -t 8h > "$ssh_env_file"
source "$ssh_env_file" >/dev/null
fi
fi
if [[ "$OSTYPE" == "darwin"* ]]; then
ssh-add --apple-load-keychain 2>/dev/null || ssh-add -A 2>/dev/null
fi
local keys=(~/.ssh/{id_ed25519,id_netease})
for key in "${keys[@]}"; do
[[ -f "$key" ]] || continue
if [[ "$OSTYPE" == "darwin"* ]]; then
ssh-add --apple-use-keychain "$key" 2>/dev/null || ssh-add "$key" 2>/dev/null
else
ssh-add "$key" 2>/dev/null
fi
done
}
# [优化] &! 表示在后台异步运行,且不受 shell 退出影响(disowned)
ssh_agent_start &!
# ------------------------------------------------------------------------------
# 7. 开发工具(延迟加载)
# ------------------------------------------------------------------------------
# pyenv
if [[ -d "$HOME/.pyenv" ]]; then
pyenv() {
unset -f pyenv
export PYENV_ROOT="$HOME/.pyenv"
path=("$PYENV_ROOT/bin" $path)
eval "$(command pyenv init - zsh)"
eval "$(pyenv virtualenv-init -)" 2>/dev/null
pyenv "$@"
}
fi
# fnm - Node.js 版本管理
# [说明] --use-on-cd 会在每次 cd 时检查 .nvmrc/.node-version,按需切换版本。
if command -v fnm &>/dev/null; then
eval "$(fnm env --use-on-cd)"
fi
# SDKMAN - Java 版本管理(延迟加载)
if [[ -s "$SDKMAN_DIR/bin/sdkman-init.sh" ]]; then
# [修复] 加 -L 跟随符号链接,并检查目录是否存在再 export,避免空值
if [[ -d "$SDKMAN_DIR/candidates/java/current" ]]; then
export JAVA_HOME="$SDKMAN_DIR/candidates/java/current"
# [优化] 同步更新 path 数组,确保 java/javac 命令可用
path=("$JAVA_HOME/bin" $path)
fi
sdk() {
unset -f sdk
source "$SDKMAN_DIR/bin/sdkman-init.sh"
sdk "$@"
}
fi
# Bun 补全(按需加载)
[[ -s "$BUN_INSTALL/_bun" ]] && source "$BUN_INSTALL/_bun"
# ------------------------------------------------------------------------------
# 8. 别名
# ------------------------------------------------------------------------------
# 文件操作
alias ll='ls -lah'
alias la='ls -A'
alias l='ls -CF'
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
# 目录导航
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'
# [修复] alias -- -= 兼容性不稳定,用函数替代更健壮
cdprev() { cd - }
alias -- -='cdprev'
# Git
alias g='git'
alias gs='git status'
alias ga='git add'
alias gc='git commit'
alias gcm='git commit -m'
alias gca='git commit --amend'
alias gp='git push'
alias gl='git pull'
alias gd='git diff'
alias gdc='git diff --cached'
alias gco='git checkout'
alias gcb='git checkout -b'
alias gb='git branch'
alias gbd='git branch -d'
alias glog='git log --oneline --graph --decorate -15'
alias gloga='git log --oneline --graph --decorate --all -20'
alias gst='git stash'
alias gstp='git stash pop'
alias grb='git rebase'
alias grbi='git rebase -i'
alias gcp='git cherry-pick'
# 实用工具
alias cls='clear'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
alias df='df -h'
alias du='du -h'
alias reload='source ~/.zshrc && echo "✓ .zshrc reloaded"'
alias path='echo $PATH | tr ":" "\n" | nl'
alias serve='python3 -m http.server'
alias ports='lsof -i -P | grep LISTEN'
# macOS 特定
alias showfiles='defaults write com.apple.finder AppleShowAllFiles YES; killall Finder'
alias hidefiles='defaults write com.apple.finder AppleShowAllFiles NO; killall Finder'
alias cleanup='find . -type f -name "*.DS_Store" -ls -delete'
# ------------------------------------------------------------------------------
# 9. 自定义函数
# ------------------------------------------------------------------------------
mkcd() { mkdir -p "$1" && cd "$1" }
ff() { find . -type f -name "*$1*" 2>/dev/null }
showpath() { echo "$PATH" | tr ':' '\n' | nl }
extract() {
if [[ ! -f "$1" ]]; then
echo "'$1' 不是有效文件"
return 1
fi
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' 无法被 extract() 解压" ;;
esac
}
proj() {
local projects_dir="$HOME/projj"
cd "${projects_dir}${1:+/$1}"
}
port() {
[[ -z "$1" ]] && { echo "Usage: port <port_number>"; return 1 }
lsof -i ":$1"
}
killport() {
[[ -z "$1" ]] && { echo "Usage: killport <port_number>"; return 1 }
local pids=$(lsof -ti ":$1")
if [[ -z "$pids" ]]; then
echo "No process found on port $1"
return 1
fi
echo "$pids" | xargs kill -9 && echo "✓ Killed process(es) on port $1"
}
# ------------------------------------------------------------------------------
# 10. 插件加载(必须在自定义配置之后,syntax-highlighting 必须最后)
# ------------------------------------------------------------------------------
if [[ -f "$HOMEBREW_PREFIX/share/zsh-autosuggestions/zsh-autosuggestions.zsh" ]]; then
source "$HOMEBREW_PREFIX/share/zsh-autosuggestions/zsh-autosuggestions.zsh"
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8'
ZSH_AUTOSUGGEST_STRATEGY=(history completion)
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=20
fi
# ⚠️ zsh-syntax-highlighting 必须最后加载
if [[ -f "$HOMEBREW_PREFIX/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" ]]; then
source "$HOMEBREW_PREFIX/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh"
fi
# Starship 提示符
eval "$(starship init zsh)"
# ------------------------------------------------------------------------------
# 11. Ghostty 终端集成
# ------------------------------------------------------------------------------
if [[ "$TERM_PROGRAM" == "ghostty" ]]; then
if [[ -f "$HOME/.config/ghostty/shell-integration.zsh" ]]; then
source "$HOME/.config/ghostty/shell-integration.zsh"
fi
fi
# ------------------------------------------------------------------------------
# 12. 本地配置(机器特定、敏感信息,不纳入版本控制)
# ------------------------------------------------------------------------------
[[ -f ~/.zshrc.local ]] && source ~/.zshrc.local
# ------------------------------------------------------------------------------
# 13. 性能分析(调试用,取消注释后配合顶部 zmodload 使用)
# ------------------------------------------------------------------------------
# zprof
# ==============================================================================
# End of .zshrc
#
# 快速参考:
# - reload 重新加载配置
# - showpath 显示 PATH
# - mkcd <dir> 创建并进入目录
# - extract <file> 智能解压文件
# - port <number> 查看端口占用
# - killport <num> 杀死端口进程
# - proj [name] 切换到项目目录
# ==============================================================================