-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path.zshrc
More file actions
636 lines (531 loc) · 17.1 KB
/
Copy path.zshrc
File metadata and controls
636 lines (531 loc) · 17.1 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
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
# ZSH CONFIG
# Required: curl, docker, git, lsof
# zmodload zsh/zprof # Debug performance (keep @ start)
# Brew
test -d /home/linuxbrew/.linuxbrew && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
test -d /opt/homebrew/bin/brew && eval "$(/opt/homebrew/bin/brew shellenv zsh)"
###
# Zshrc helper
###
preexec() {
local after="${1##*|}"
[[ "$after" =~ ^[[:space:]]*copy([[:space:]]|$) ]] && _last_cmd="${1%|*}" || _last_cmd="$1"
}
function _zcompile-many() {
local f
for f; do zcompile -R -- "$f".zwc "$f"; done
}
function _debug_log() {
[ "$DEBUG" = "true" ] && echo "DEBUG: $*" >&2
}
function _check-commands() {
local missing=()
for cmd in "$@"; do
if ! command -v "$cmd" &>/dev/null; then
missing+=("$cmd")
fi
done
if [ ${#missing[@]} -gt 0 ]; then
echo "Missing commands: ${missing[*]}"
return 1
fi
return 0
}
function _ask() {
local prompt="$1"
local response
echo "$prompt (y/N) "
read -r response
[[ "$response" == [yY] ]] && return 0 || return 1
}
function _link-if-missing() {
local source="$1"
local target="$2"
[[ -e "$target" ]] && return 0
if [[ ! -e "$source" ]]; then
echo "No source found for $target at $source, skipping." >&2
return 1
fi
_ask "$target is missing. Create symlink (sudo required in next step)?" || return 0
sudo ln -s "$source" "$target"
echo "Linked $target -> $source"
}
function _detect_platform() {
case "$(uname -s)" in
Darwin)
echo "macos"
;;
Linux)
if grep -qi microsoft /proc/version 2>/dev/null; then
echo "wsl"
else
echo "linux"
fi
;;
MINGW* | MSYS* | CYGWIN*)
echo "windows"
;;
*)
echo "unknown"
;;
esac
}
function _detect_linux_distro() {
[[ -f /etc/alpine-release ]] && echo "alpine" && return
echo "debian"
}
PLATFORM="$(_detect_platform)"
LINUX_DISTRO=""
[[ "$PLATFORM" == "linux" ]] && LINUX_DISTRO="$(_detect_linux_distro)"
if _check-commands starship; then
eval "$(starship init zsh)"
fi
[[ "$TERM_PROGRAM" == "vscode" ]] && . "$(code --locate-shell-integration-path zsh)"
###
# Basics
###
RICE_HOME="$HOME/.dotfiles"
export XDG_CACHE="$HOME/.cache/"
export ZSH_CONFIG="$HOME/.config/zsh"
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
export AUTOSOURCE=1
export WORDCHARS='*?_-.[]~=&;!#$%^(){}<>' # where not to stop for word navigation
# Clone missing plugins
if [[ ! -e "$ZSH_CONFIG/fzf-tab" ]]; then
git clone git@github.com:Aloxaf/fzf-tab.git "$ZSH_CONFIG/fzf-tab"
fi
if [[ ! -e "$ZSH_CONFIG/alias-tips" ]]; then
git clone https://github.com/djui/alias-tips.git "$ZSH_CONFIG/alias-tips"
fi
# Compile missing plugins
if [[ ! -e "$XDG_CACHE/completion-for-pnpm.zsh" ]]; then
pnpm completion zsh >"$XDG_CACHE/completion-for-pnpm.zsh"
fi
# Set PATH
export PATH=$HOME/.local/bin:$PATH
export PATH=$HOME/.local/share/mise/installs/go/latest/bin:$PATH
export PATH=$HOME/.horiceon/bin:$PATH
# History
export HISTSIZE=100000 # 7y of 100 commands/day
export SAVEHIST=$HISTSIZE
# Options
# https://zsh.sourceforge.io/Doc/Release/Options.html
setopt AUTO_CD # automatic directory change
setopt BANG_HIST # perform textual history expansion, csh-style, treating the character ‘!’ specially
setopt EXTENDED_HISTORY # write the history file in the ":start:elapsed;command" format.
setopt GLOBDOTS # hidden files globbing
setopt HIST_EXPIRE_DUPS_FIRST # trim dupes first if history is full
setopt HIST_FIND_NO_DUPS # do not display previously found command
setopt HIST_IGNORE_SPACE # do not save if line starts with space
setopt HIST_NO_FUNCTIONS # do not save function commands
setopt HIST_REDUCE_BLANKS # strip superfluous blanks
setopt INC_APPEND_HISTORY # write to the history file immediately, not when the shell exits.
setopt INTERACTIVE_COMMENTS # ignore commands starting with hashtag
setopt NO_CASE_GLOB # case insensitive globbing
setopt SHARE_HISTORY # share history between all sessions.
# Set completion PATH
FPATH="$(brew --prefix)/share/zsh/site-functions:$HOME/.zsh/completions:$FPATH"
# User settings
export GIT_SEQUENCE_EDITOR="code --wait --diff"
export FZF_DEFAULT_OPTS="--height 90% --layout=reverse"
# Completion Settings
zstyle ':completion:*' completer _complete _ignored _expand_alias
zstyle ':completion:*:git-checkout:*' sort false
# preview content or directory's content with eza when completing
zstyle ':fzf-tab:complete:*:*' fzf-preview '
if [[ -f "$realpath" ]]; then
bat --color=always --style=numbers --line-range=:500 "$realpath" 2>/dev/null \
|| file --brief "$realpath"
elif [[ -d "$realpath" ]]; then
eza -la --color=always "$realpath"
elif [[ -n "$desc" ]]; then
echo "$word -- $desc" | fold -s -w "${FZF_PREVIEW_COLUMNS:-80}"
fi
'
# zstyle ':fzf-tab:*' continuous-trigger tab # chain completions: cd /usr/[TAB] -> pick dir -> TAB again without re-typing
zstyle ':fzf-tab:*' switch-group '<' '>' # switch group using `<` and `>`
# Enable the "new" completion system (compsys)
autoload -Uz compinit && compinit
[[ ~/.zcompdump.zwc -nt ~/.zcompdump ]] || _zcompile-many ~/.zcompdump
unfunction _zcompile-many
###
# Plugins
###
source "$(brew --prefix)/opt/fzf/shell/completion.zsh"
source "$(brew --prefix)/opt/fzf/shell/key-bindings.zsh"
source "$(brew --prefix)/share/zsh/site-functions"
source "$ZSH_CONFIG/fzf-tab/fzf-tab.plugin.zsh"
source "$ZSH_CONFIG/alias-tips/alias-tips.plugin.zsh"
source "$XDG_CACHE/completion-for-pnpm.zsh"
source "$HOME/.cargo/env"
###
# Keybinds
###
bindkey -e # emacs mode
###
# User space
###
alias "..."="cd ../.."
alias "...."="cd ../../.."
alias finder="open"
alias grepf="fzf -f"
alias horiceon="/usr/bin/git --git-dir=$RICE_HOME --work-tree=$HOME"
alias la="ls -la"
alias now="date +%s"
alias rm="trash"
alias timestamp="date +%s"
alias la="ls -la"
case "$PLATFORM" in
macos)
alias open-file='open'
alias install='brew install'
alias clipboard='pbcopy'
alias pasteboard='pbpaste'
;;
wsl)
alias open-file='explorer.exe'
alias install='sudo apt-get install'
alias clipboard='clip.exe'
alias pasteboard='powershell.exe -NoProfile -Command Get-Clipboard | tr -d "\r"'
;;
linux)
alias open-file='xdg-open'
case "$LINUX_DISTRO" in
alpine) alias install='sudo apk add' ;;
debian) alias install='sudo apt-get install' ;;
esac
if command -v xclip &>/dev/null; then
alias clipboard='xclip -selection clipboard'
alias pasteboard='xclip -selection clipboard -o'
elif command -v wl-copy &>/dev/null; then
alias clipboard='wl-copy'
alias pasteboard='wl-paste'
fi
;;
esac
alias wttr="curl 'https://wttr.in/?view=v1&output=txt&no-terminal=true&emoji=plain&superquiet=true&narrow=true&days=1'"
function cheat {
curl "cht.sh/$1" | less -R
}
alias example="cheat"
alias expl="cheat"
alias explain="cheat"
alias tldr="cheat"
alias help="cheat"
function til() {
target=$(date -j -f "%H:%M" "$1" "+%s")
now=$(date +%s)
sleep $((target - now))
}
[[ "$PLATFORM" == "macos" ]] && alias unquarantine="xattr -rd com.apple.quarantine"
function check-port() {
lsof -i tcp${1:+":$1"}
}
function kill_port() {
if [ "$#" -ne 1 ]; then
echo "Usage: kill_port <PORT>"
return 1
fi
PORT=$1
PID=$(lsof -t -i tcp:$PORT)
if [ -z "$PID" ]; then
echo "No process found running on port $PORT"
return 1
fi
echo "Killing process $PID running on port $PORT"
kill -9 $PID
}
function copy() {
local include_cmd=false
[[ "$1" == "-c" ]] && include_cmd=true
local content=$(cat)
printf '%s\n' "$content"
if $include_cmd; then
printf '%s\n%s\n' "$_last_cmd" "$content" | clipboard
else
printf '%s\n' "$content" | clipboard
fi
}
function alpine() {
function _help() {
echo "Usage: alpine [--pkg=PKG] <binary> [args...]"
echo "Example: 'alpine --pkg=android-tools adb pair 192.168.172.123:45678 123456'"
}
local package=$1
if [[ "$1" == --pkg=* ]]; then
package="${1#--pkg=}"
shift
elif [[ "$1" == --pkg ]]; then
echo "Error: --pkg requires a value (use --pkg=VALUE)\n"
_help
return 1
fi
if [ $# -lt 1 ]; then
_help
return 1
fi
local bin=$1
shift
docker run --rm -it --init -v "$(pwd)":/app -w /app alpine:latest sh -c "apk add --quiet $package && $bin \"\$@\"" -- "$@"
}
if _check-commands docker; then
function command_not_found_handler() {
local cmd=$1
if [[ ! -t 0 ]]; then
echo "Command '$cmd' not found"
return 127
fi
echo
echo "Command '$cmd' not found. Try with alpine? [y/N]"
read -k 1 run_response
if [[ $run_response == "y" || $run_response == "Y" ]]; then
shift
alpine $cmd "$@"
fi
return 127
}
fi
function alias-suggest() {
local noise='awk|sort|head'
fc -l 1 |
# Drop the leading history event number.
sed -E 's/^[[:space:]]*[0-9]+[[:space:]]*//' |
# Split pipelines into separate command segments and unescape.
sed -E 's/\\n/ /g; s/ \| /\n/g; s/\\//g' |
# Trim surrounding whitespace, drop blank lines.
awk 'NF { $1=$1; print }' |
# Keep lines that look like a command invocation...
grep -E '^[a-zA-Z/~.]' |
# ...excluding noise commands and any leftover pipelines...
grep -Ev "^($noise) " |
grep -v '|' |
# ...and excluding assignments or quoted strings.
awk '$1 !~ /["=]/ && $1 ~ /[a-z]/' |
# Normalize: expand the leading command word so `g status` and
# `git status` (where g=git) contribute to the same count.
while read -r line; do
local cmd="${line%% *}"
local rest="${line#"$cmd"}"
print -r -- "${aliases[$cmd]:-$cmd}$rest"
done |
# Count identical commands, keep repeats, most frequent first.
sort | uniq -c | awk '$1 > 1' | sort -rn
}
_cli_continues="$HOME/code/cli-continues"
if [[ ! -e "$_cli_continues/dist/cli.js" ]]; then
[[ ! -d "$_cli_continues" ]] && git clone git@github.com:shiftgeist/cli-continues.git "$_cli_continues"
(cd "$_cli_continues" && pnpm install && pnpm run build)
fi
alias continues="node $_cli_continues/dist/cli.js"
alias continues-dump="continues dump ./sessions --preset full --limit 1"
if _check-commands bat; then
alias cat="bat -p"
fi
if _check-commands brew; then
function brew-bundle-dump() {
brew bundle dump --global --force --no-go --no-npm
brew bundle remove --global awscli antigravity-cli claude-code claudebar gemini-cli microsoft-teams mistral-vibe ladybird
echo "Brewfile dumped and filtered"
}
alias mise-up="cd $HOME && mise up"
alias brew-recover="brew bundle install --global && mise-up"
alias brew-up-apps="brew upgrade \
affinity \
beekeeper-studio \
blender \
bruno \
cyberduck \
figma \
iterm2 \
obsidian \
spotify \
zen"
alias brew-up="brew upgrade && brew-up-apps && mise-up"
alias brew-up-all="brew upgrade --greedy && mise-up"
alias ladybird-setup="brew create https://github.com/LadybirdBrowser/ladybird/archive/refs/heads/master.zip --set-name ladybird --set-version HEAD && echo 'Run \"brew edit ladybird\" and paste your formula code.'"
if [ -d /opt/homebrew/opt/ladybird/.brew/ladybird.rb ]; then
alias ladybird-install="HOMEBREW_NO_INSTALL_FROM_API=1 brew install --build-from-source ladybird"
alias ladybird-update="HOMEBREW_NO_INSTALL_FROM_API=1 brew upgrade --fetch-HEAD ladybird"
alias ladybird-make-app="sudo rm -rf /Applications/Ladybird.app && sudo cp -R /opt/homebrew/opt/ladybird/bundle/Ladybird.app /Applications/Ladybird.app"
alias ladybird-reinstall="HOMEBREW_NO_INSTALL_FROM_API=1 brew reinstall --build-from-source ladybird"
fi
fi
if _check-commands code; then
export VISUAL="code"
alias horiceon-code='GIT_DIR="$RICE_HOME" GIT_WORK_TREE="$HOME" code "$HOME"'
fi
if _check-commands glow; then
alias glow="glow --width \"$(tput cols)\""
fi
if _check-commands eza; then
alias exa="eza"
alias ls="eza"
fi
if _check-commands fd; then
alias fda="fd --unrestricted --full-path"
fi
if _check-commands mise; then
eval "$(mise activate zsh)"
_link-if-missing $HOME/.local/share/mise/shims/bun /usr/local/bin/bun
_link-if-missing $HOME/.local/share/mise/shims/deno /usr/local/bin/deno
_link-if-missing $HOME/.local/share/mise/shims/go /usr/local/bin/go
_link-if-missing $HOME/.local/share/mise/shims/node /usr/local/bin/node
if [[ -e "$HOME/code/dprint/target/release/dprint" ]]; then
_link-if-missing $HOME/code/dprint/target/release/dprint /usr/local/bin/dprint
else;
_link-if-missing $HOME/.local/share/mise/shims/dprint /usr/local/bin/dprint
fi
fi
if _check-commands pnpx; then
alias ts-prune="pnpx knip"
fi
if _check-commands uv; then
alias pip="uv pip"
alias bestllm="uvx whichllm@latest --profile coding"
fi
if _check-commands vim; then
export EDITOR="vim"
fi
if _check-commands yq; then
alias jq="yq"
alias yq-combine="yq ea '[.]'"
alias yqx="yq -p=xml"
function curl-pretty {
curl -s $@ | yq -P
}
function _run_exec_task() {
local tool="$1"
local name="$2"
case "$tool" in
deno) deno ${=name} ;;
make) make "$name" ;;
pnpm) pnpm "$name" ;;
*) "$tool" run "$name" ;;
esac
}
function _run_list_all_commands() {
_debug_log "_run_list_all_commands: tool=$1"
case "$1" in
deno) (NO_COLOR=1 deno help 2>&1 | awk '/^ [a-z]/ && !/:$/ { print $1 }'; NO_COLOR=1 deno run 2>&1 | awk '/^- / { print "run " $2 }') ;;
make) grep '^[[:alnum:]_.-][[:alnum:]_.-]*:' Makefile | cut -d: -f1 | grep -v '^\.PHONY$' ;;
mise) (mise help 2>&1 | awk '/^ [a-z]/ { print $1 }'; mise tasks ls --name-only) ;;
npm) (npm help 2>&1 | awk '/All commands:/,/^[^ ]/ {print}' | tr ',' '\n' | awk '/^[a-z]/ {print}'; yq -r '.scripts // {} | keys | .[]' package.json) ;;
pnpm) (pnpm help -a | sed -nE '/^Options:/q; s/^[[:space:]]*([[:alnum:]-]+, )?([[:alnum:]-]+)[[:space:]]{2,}.*/\2/p'; yq -r '.scripts // {} | keys | .[]' package.json) ;;
bun) (bun help 2>&1 | awk '/^ [a-z]/ {print $1}'; yq -r '.scripts // {} | keys | .[]' package.json) ;;
*) yq -r '.scripts // {} | keys | .[]' package.json ;;
esac | sort -u
}
function _run_list_project_tasks() {
_debug_log "_run_list_project_tasks: tool=$1"
case "$1" in
deno) NO_COLOR=1 deno run 2>&1 | awk '/^- / { print "run " $2 }' ;;
make) grep '^[[:alnum:]_.-][[:alnum:]_.-]*:' Makefile | cut -d: -f1 | grep -v '^\.PHONY$' ;;
mise) mise tasks ls --name-only ;;
*) [ -f package.json ] && yq -r '.scripts // {} | keys | .[]' package.json ;;
esac | sort -u
}
function run() {
local tool
case "$1" in
deno | npm | pnpm | bun | mise | make)
tool="$1"
_debug_log "run: explicit tool='$tool' given as \$1"
shift
;;
*)
if [ -f ".mise.toml" ] || [ -f "mise.toml" ]; then
tool="mise"
elif [ -f "Makefile" ]; then
tool="make"
elif [ -f "deno.json" ]; then
tool="deno"
elif [ -f "package.json" ]; then
if [ -f "pnpm-lock.yaml" ]; then
tool="pnpm"
elif [ -f "bun.lockb" ] || [ -f "bun.lock" ]; then
tool="bun"
else
tool="npm"
fi
else
_debug_log "run: no project file matched"
echo "RUN: No recognized project file found (mise.toml / Makefile / deno.json / package.json)"
return 1
fi
_debug_log "run: auto-detected tool='$tool'"
;;
esac
local tool_file
case "$tool" in
deno) tool_file="deno.json" ;;
make) tool_file="Makefile" ;;
mise) tool_file=".mise.toml, mise.toml" ;;
bun|npm|pnpm) tool_file="package.json" ;;
esac
local task="$1"
_debug_log "run: task='$task' tool='$tool'"
local names=$(_run_list_all_commands "$tool")
_debug_log "run: available tasks=[$(echo "$names" | tr '\n' ' ')]"
if [ -z "$names" ]; then
_debug_log "run: no tasks found via $tool_file"
echo "RUN: No task available for $tool. Check $tool_file."
return
fi
if [ -z "$task" ]; then
_debug_log "run: no task argument given, listing tasks"
echo "RUN: Task not given"
echo "Usage: run [command]\n"
echo "Available tasks ($tool):"
echo "$names"
return
fi
# exact match: run directly
if echo "$names" | grep -qxF -- "$task"; then
_debug_log "run: exact match found for '$task'"
echo "RUN: Found exact match. Running \"_run_exec_task "$tool" "$task"\""
_run_exec_task "$tool" "$task"
return
fi
# fuzzy match
local matches count
matches=$(echo "$names" | grep -iE -- "$task")
count=$(echo "$matches" | grep -c .)
_debug_log "run: fuzzy match count=$count matches=[$(echo "$matches" | tr '\n' ' ')]"
if [ "$count" -eq 0 ]; then
echo "RUN: No tasks matching '$task'"
return 1
elif [ "$count" -eq 1 ]; then
echo "RUN: Running \"$matches\" with $tool"
sleep 0.3
_run_exec_task "$tool" "$matches"
else
echo "$matches"
fi
}
alias B="run build"
alias D="run dev"
alias T="run test"
alias I="run install"
fi
if _check-commands zoxide; then
export _ZO_DOCTOR=0
eval "$(zoxide init zsh)"
alias cd="z"
alias cdi="zi"
fi
###
# WSL setups
###
if [[ $IS_WSL ]]; then
if _check-commands powershell.exe; then
value="$(powershell.exe -NoProfile -Command "(Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock' -Name AllowDevelopmentWithoutDevLicense -ErrorAction SilentlyContinue).AllowDevelopmentWithoutDevLicense" 2>/dev/null | tr -d '\r')"
[[ "$value" == "1" ]] && DEV_MODE_ENABLED=true
[[ $DEV_MODE_ENABLED ]] || echo "Developer mode is turned off (System > Advanced > Section "For developers" - Developer Mode = on)"
fi
if [[ $(command -v apt-get) ]]; then
alias apt-setup="sudo apt-get install trash-cli"
fi
_link-if-missing /mnt/c/Users/user/ "$HOME/c/"
_link-if-missing "$HOME/dotfiles/vscode/settings.json" /mnt/c/Users/user/AppData/Roaming/Code/User/settings.json
fi
# zprof # Debug performance (keep @ bottom)