-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathdot_zshrc
More file actions
277 lines (242 loc) · 10.4 KB
/
Copy pathdot_zshrc
File metadata and controls
277 lines (242 loc) · 10.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#-----------------------------------------------------------
# @raisedadead's config files
# Copyright: Mrugesh Mohapatra <https://mrugesh.dev>
# License: ISC
#
# File name: .zshrc
#-----------------------------------------------------------
# Performance profiling (set ZPROF=true to enable)
[[ "$ZPROF" = true ]] && zmodload zsh/zprof
# TEMPORARY cold-start TTI trace. Enable: touch ~/.tti-trace-on — logs per-segment
# ms to /tmp/tti.log. No-op (single empty fn call) when marker absent. Remove block
# after diagnosis.
if [[ -f ~/.tti-trace-on ]]; then
zmodload zsh/datetime
autoload -Uz add-zsh-hook
typeset -g _TTI_T0=$EPOCHREALTIME _TTI_TP=$EPOCHREALTIME
_tti() {
printf '%8.1f +%7.1f %s\n' \
$(( (EPOCHREALTIME-_TTI_T0)*1000 )) $(( (EPOCHREALTIME-_TTI_TP)*1000 )) "$1" >> /tmp/tti.log
_TTI_TP=$EPOCHREALTIME
}
_tti_prompt_ready() { _tti prompt-ready; add-zsh-hook -d precmd _tti_prompt_ready; unfunction _tti_prompt_ready; }
add-zsh-hook precmd _tti_prompt_ready
print -r -- "---- $(strftime '%Y-%m-%d %H:%M:%S' $EPOCHSECONDS) tmux=${TMUX:+1} ----" >> /tmp/tti.log
_tti start
else
_tti() { }
fi
#-----------------------------------------------------------
# Core Settings
#-----------------------------------------------------------
umask 022
limit coredumpsize 0
# History
HISTFILE="$HOME/.zsh_history"
HISTSIZE=50000
SAVEHIST=50000
setopt INC_APPEND_HISTORY
setopt HIST_EXPIRE_DUPS_FIRST
setopt HIST_IGNORE_DUPS
setopt HIST_IGNORE_ALL_DUPS
setopt HIST_IGNORE_SPACE
setopt HIST_FIND_NO_DUPS
setopt HIST_SAVE_NO_DUPS
# Options
setopt AUTO_CD
setopt AUTO_PUSHD
setopt PUSHD_IGNORE_DUPS
setopt CDABLE_VARS
setopt INTERACTIVECOMMENTS
stty -ixon -ixoff 2>/dev/null
# Helpers
can_haz() { whence -p "$1" >/dev/null 2>&1 }
timezsh() { for i in {1..10}; do time zsh -i -c exit; done }
# Cache and source tool-generated shell code (regenerates when binary updates)
# Usage: cached_evalz <tool> "<command>"
cached_evalz() {
local tool=$1 cmd=$2 cache_dir="$HOME/.cache/zsh-eval-cache"
can_haz "$tool" || return 1
local bin="$(whence -p "$tool")" cache="$cache_dir/$tool.zsh" tmp
[[ -d "$cache_dir" ]] || mkdir -p "$cache_dir"
if [[ ! -f "$cache" ]] || [[ "$bin" -nt "$cache" ]]; then
tmp="$(mktemp "$cache_dir/.${tool}.XXXXXX")"
if eval "$cmd" > "$tmp" 2>/dev/null; then
# Validate first non-blank line looks like zsh script, not a banner.
# Accept: comments (#...), shebangs, common zsh declarations, block openers.
local first
first="$(awk 'NF{print;exit}' "$tmp")"
case "$first" in
'#'*|'{'*|'('*|compdef\ *|function\ *|typeset\ *|export\ *|alias\ *|setopt\ *|autoload\ *|local\ *|zstyle\ *|bindkey\ *|source\ *|eval\ *|_*\(\)*)
mv "$tmp" "$cache" && zcompile "$cache" 2>/dev/null ;;
*)
rm -f "$tmp"
print -u2 "cached_evalz: $tool: output does not look like zsh (first line: ${first:0:60}...) — cache skipped"
return 1 ;;
esac
else
rm -f "$tmp"
return 1
fi
fi
source "$cache"
}
# Tmux exit code indicator (must be first precmd to capture $? before OMP)
_tmux_exit_code() { [[ -n "$TMUX" ]] && tmux set-option -qw @last_exit_code $?; }
precmd_functions=(_tmux_exit_code $precmd_functions)
# Keybindings
bindkey -e # Emacs mode
bindkey '^z' vi-cmd-mode
bindkey -M vicmd '^z' vi-add-next
function zle-keymap-select {
if [[ "$KEYMAP" == "vicmd" ]]; then
export POSH_VI_MODE="cmd"
else
unset POSH_VI_MODE
fi
# Re-generate OMP prompt (reads updated POSH_VI_MODE), then redisplay
if (( $+functions[_omp_get_prompt] )); then
eval "$(_omp_get_prompt primary --eval)"
fi
zle .reset-prompt
}
zle -N zle-keymap-select
bindkey '^[l' forward-word # Alt+L: forward word
bindkey '^[h' backward-word # Alt+H: backward word
bindkey '^[L' end-of-line # Alt+Shift+L: end of line
bindkey '^[H' beginning-of-line # Alt+Shift+H: beginning of line
bindkey '^[[1;3C' forward-word # Alt+Right: forward word
bindkey '^[[1;3D' backward-word # Alt+Left: backward word
bindkey '^[[1;4C' end-of-line # Alt+Shift+Right: end of line
bindkey '^[[1;4D' beginning-of-line # Alt+Shift+Left: beginning of line
# Prompt (oh-my-posh)
# v29+ uses a two-stage init: bootstrap sets a precmd that sources the real
# init from ~/.cache/oh-my-posh/init.HASH.zsh on first prompt. OMP manages
# its own cache, so we just run the bootstrap directly.
if can_haz oh-my-posh; then
eval "$(oh-my-posh init zsh --config ~/.config/oh-my-posh/config.toml)"
fi
_tti omp-init
#-----------------------------------------------------------
# Plugin Manager
#-----------------------------------------------------------
ZINIT_HOME="${XDG_DATA_HOME:-${HOME}/.local/share}/zinit/zinit.git"
[[ ! -d $ZINIT_HOME ]] && mkdir -p "$(dirname $ZINIT_HOME)" && git clone https://github.com/zdharma-continuum/zinit.git "$ZINIT_HOME"
source "$ZINIT_HOME/zinit.zsh"
#-----------------------------------------------------------
# Load zsh-defer first
zinit light romkatv/zsh-defer
# FZF - core setup (DO NOT DEFER, need immediate availability)
source ~/.fzf.zsh
# FZF styling (can be deferred)
zsh-defer source ~/.fzf.zshrc
# zinit compile, compinit rebuild, rc zcompile, and OMP cache reap run together in
# one disowned background block near the end (see "Daily maintenance"). They used to
# be tail-of-queue zsh-defer tasks that starved: a pane opened straight into a
# long-running command (claude/nvim) never idles at the prompt, so the queue never
# drained that far — leaving the compdump 3+ days stale and the OMP cache unreaped.
# Load completions before compinit (per zsh-completions guidelines)
zinit light zsh-users/zsh-completions
zinit light wbingli/zsh-claudecode-completion
_tti zinit-sync
# Add Homebrew completions to FPATH before compinit
[[ -n "$HOMEBREW_PREFIX" ]] && FPATH="$HOMEBREW_PREFIX/share/zsh/site-functions:$FPATH"
# Add custom completions to FPATH (highest priority - added last so it's first)
[[ -d ~/.zfunc ]] && FPATH="$HOME/.zfunc:$FPATH"
# Load completions. Critical path ALWAYS uses the cached -C load (~12ms); the
# full rebuild (compaudit fpath scan, ~344ms) is deferred off the prompt path.
# Stale dump costs a fast shell now + a freshly-rebuilt dump next shell.
autoload -Uz compinit
local zcomp="$HOME/.zcompdump"
if [[ -f "$zcomp" ]]; then
compinit -C -d "$zcomp"
else
compinit -d "$zcomp"
fi
_tti compinit
# (deferred full rebuild moved to the background maintenance block below)
# FZF tab (must load after compinit but before widget-wrapping plugins)
zinit wait"0a" silent for \
Aloxaf/fzf-tab
zsh-defer -c "
zstyle ':fzf-tab:*' use-fzf-default-opts yes
zstyle ':fzf-tab:*' fzf-flags --height=~60%
"
# Fast Syntax Highlighting
zinit wait"1a" silent atload"fast-theme -q XDG:catppuccin-mocha" for \
zdharma-continuum/fast-syntax-highlighting
# Suggestions
zinit wait"1b" silent atload"!_zsh_autosuggest_start" for \
zsh-users/zsh-autosuggestions
# Pair matching
zinit wait"1c" silent for \
raisedadead/zsh-smartinput
# PNPM completions
zinit wait"1d" silent atload"zpcdreplay" atclone"./zplug.zsh" atpull"%atclone" for \
g-plane/pnpm-shell-completion
# Touch file with paths
zinit wait"2a" silent for \
raisedadead/zsh-touchplus
# Wakatime
zinit wait"2b" silent for \
sobolevn/wakatime-zsh-plugin
#-----------------------------------------------------------
# Tool Integrations
#-----------------------------------------------------------
if [[ -o interactive ]]; then
# Async inits: first prompt renders before these spawn their per-shell binaries
# (atuin sources $(atuin uuid); direnv's precmd spawns `direnv export`) — cold-cache
# execs that stall seconds. Hooks go live on first zle-idle, before any keystroke.
# Trade: a shell opened inside a direnv dir loads .envrc one precmd late.
zsh-defer cached_evalz atuin "atuin init zsh --disable-up-arrow"
zsh-defer _tti d-atuin
zsh-defer cached_evalz zoxide "zoxide init --cmd cd --hook pwd zsh"
zsh-defer cached_evalz direnv "direnv hook zsh"
zsh-defer _tti d-cd-hooks
# Completions only matter at first Tab, not first keystroke — defer off the
# critical path. zsh-defer (q)-quotes each arg and evals it verbatim on zle idle.
zsh-defer cached_evalz gh "gh completion -s zsh"
zsh-defer cached_evalz op "op completion zsh"
zsh-defer compdef _op op
zsh-defer cached_evalz wrangler "wrangler complete zsh | sed -n '/^#compdef/,\$p'" # strip pre-#compdef banner (wrangler 4.94+ leaks skills-install nag to stdout)
zsh-defer cached_evalz wt "wt shell-init zsh"
zsh-defer cached_evalz bd "bd completion zsh"
zsh-defer compdef _home home
zsh-defer _tti d-completions
fi
# File sourcing
zsh-defer source ~/.alias.zshrc
zsh-defer source ~/.private.zshrc
zsh-defer -c '[[ -f "$HOME/.local/bin/env" ]] && source "$HOME/.local/bin/env"'
zsh-defer -c '[[ -f ~/.bin/functions.sh ]] && source ~/.bin/functions.sh'
# Daily maintenance — disowned background subshell (&!) so it completes regardless of
# whether the shell ever idles at the prompt. Guards keep the heavy work to ~once/day;
# on most shells every branch is skipped and the subshell exits immediately. Output is
# silenced so async completion never bleeds onto the terminal. None of this feeds the
# current shell (the critical-path `compinit -C` already ran), so background is safe.
{
local _now=$(date +%s)
local _stamp="$HOME/.cache/zinit-compile-stamp" _zcomp="$HOME/.zcompdump"
if [[ ! -f "$_stamp" ]] || (( _now - $(stat -f%m "$_stamp" 2>/dev/null || echo 0) > 86400 )); then
zinit compile --all 2>/dev/null; touch "$_stamp"
fi
if [[ ! -f "$_zcomp" ]] || (( _now - $(stat -f%m "$_zcomp" 2>/dev/null || echo 0) > 86400 )); then
autoload -Uz compinit && compinit -d "$_zcomp"
fi
for f in ~/.zshrc ~/.zshenv ~/.alias.zshrc; do
[[ -f "$f" && ( ! -f "$f.zwc" || "$f" -nt "$f.zwc" ) ]] && zcompile "$f"
done
setopt extended_glob null_glob
local -a _c=( ~/.cache/oh-my-posh/(shell|zsh).*.omp.cache(om) )
(( $#_c > 50 )) && rm -f "${_c[51,-1]}"
} >/dev/null 2>&1 &!
zsh-defer _tti d-done
# Homebrew must precede /usr/bin in PATH to avoid system binaries taking priority.
# fnm must load after Homebrew so fnm-managed Node.js overrides Homebrew's Node.js.
export PATH="/opt/homebrew/bin:$PATH"
cached_evalz fnm "fnm env --use-on-cd --version-file-strategy=recursive --resolve-engines --log-level=quiet"; _tti fnm
# Performance profiling
[[ "$ZPROF" = true ]] && zprof
#-----------------------------------------------------------
# End of .zshrc
#-----------------------------------------------------------