1# macOS hands GUI-launched processes a 256 fd soft limit, which bundler
2# file watchers exhaust during their first build.
3ulimit -n 65536 2>/dev/null
4
5function _update_prompt_theme() {
6 if [[ "$(defaults read -g AppleInterfaceStyle 2>/dev/null)" == "Dark" ]]; then
7 PS1="%{$(tput setaf 207)%}%m%{$(tput setaf 15)%}:%{$(tput setaf 87)%}%~ %{$(tput sgr0)%}$ "
8 else
9 PS1="%{$(tput setaf 168)%}%m%{$(tput setaf 238)%}:%{$(tput setaf 33)%}%~ %{$(tput sgr0)%}$ "
10 fi
11}
12precmd_functions+=(_update_prompt_theme)
13_update_prompt_theme
14
15function python() {
16 dirname=$(dirname $1 2>/dev/null)
17 if [ -z "$dirname" ]; then
18 dirname=$(pwd)
19 fi
20 uv run --project "$dirname" "$@"
21}
22
23function bun() {
24 if [[ "$1" = "build" ]]; then
25 command bun run "$@"
26 elif [[ "$1" = "bundle" ]]; then
27 shift
28 command bun build "$@"
29 else
30 command bun "$@"
31 fi
32}
33
34function pr() {
35 local branch remote repo url
36 branch="$(
37 command jj log -r '@ | @-' -T 'bookmarks.map(|b| b.name()).join("\n") ++ "\n"' --no-graph 2>/dev/null |
38 while IFS= read -r bookmark; do
39 case "$bookmark" in
40 "" | main | master | trunk | deployment*) ;;
41 *) printf '%s' "$bookmark"; break ;;
42 esac
43 done
44 )"
45 if [ -z "$branch" ]; then
46 printf 'no jj bookmark found on @ or @-\n' >&2
47 return 1
48 fi
49
50 remote="$(
51 command jj git remote list 2>/dev/null |
52 while IFS=' ' read -r name remote_url _; do
53 if [ "$name" = "origin" ]; then
54 printf '%s' "$remote_url"
55 break
56 fi
57 done
58 )"
59 case "$remote" in
60 git@github.com:*) repo="${remote#git@github.com:}" ;;
61 ssh://git@github.com/*) repo="${remote#ssh://git@github.com/}" ;;
62 https://github.com/*) repo="${remote#https://github.com/}" ;;
63 http://github.com/*) repo="${remote#http://github.com/}" ;;
64 *)
65 printf 'origin is not a github remote: %s\n' "$remote" >&2
66 return 1
67 ;;
68 esac
69
70 repo="${repo%.git}"
71 url="https://github.com/$repo/pull/new/$branch?labels=auto-merge"
72 command open "$url"
73}
74
75function _jjImmutableRevision() {
76 emulate -L zsh
77 setopt extendedglob
78 local line
79 while IFS= read -r line; do
80 line="${line//$'\e'\[[0-9;]##m/}"
81 if [[ "$line" = *"Could not modify commit: "* ]]; then
82 line="${line#*Could not modify commit: }"
83 printf '%s' "${line%% *}"
84 return 0
85 fi
86 done < "$1"
87 return 1
88}
89
90function _runJjStreaming() {
91 emulate -L zsh
92 setopt no_multios
93 local stderr arg has_color
94 local -a jj_color_arg pipe_status
95 stderr="$1"
96 shift
97 if [[ -t 1 && -t 2 ]]; then
98 has_color=false
99 for arg in "$@"; do
100 if [[ "$arg" = "--color" || "$arg" = --color=* ]]; then
101 has_color=true
102 break
103 fi
104 done
105 if ! $has_color; then
106 jj_color_arg=(--color=always)
107 fi
108 fi
109 {
110 command jj "$jj_color_arg[@]" "$@" 2>&1 1>&3 | tee "$stderr" >&2
111 pipe_status=("${pipestatus[@]}")
112 } 3>&1
113 return $pipe_status[1]
114}
115
116function _jjHandleFailure() {
117 local stderr jj_status reply
118 stderr="$1"
119 jj_status="$2"
120 shift 2
121 if [[ $jj_status -ne 0 ]]; then
122 if _jjImmutableRevision "$stderr" >/dev/null && [[ -t 0 ]]; then
123 printf 'Rewrite immutable commit anyways [y/N] ' >&2
124 read -r reply
125 case "$reply" in
126 [Yy] | [Yy][Ee][Ss])
127 _runJj "$@" --ignore-immutable
128 return $?
129 ;;
130 esac
131 return $jj_status
132 fi
133 fi
134 return $jj_status
135}
136
137function _runJj() {
138 local stderr jj_status
139 stderr="$(mktemp)"
140 _runJjStreaming "$stderr" "$@"
141 jj_status=$?
142 _jjHandleFailure "$stderr" "$jj_status" "$@"
143 jj_status=$?
144 rm -f "$stderr"
145 return $jj_status
146}
147
148function wrapWithAutoInstall() {
149 local root file cmd before after wrapped_status
150 root="$(command jj workspace root)"
151 if [ -n "$root" ]; then
152 if [ -e "$root/bun.lock" ]; then
153 file="$root/bun.lock"
154 cmd="bun i -f"
155 elif [ -e "$root/package-lock.json" ]; then
156 file="$root/package-lock.json"
157 cmd="npm i"
158 elif [ -e "$root/pnpm-lock.yaml" ]; then
159 file="$root/pnpm-lock.yaml"
160 cmd="pnpm i"
161 elif [ -e "$root/Cargo.lock" ]; then
162 file="$root/Cargo.lock"
163 cmd="cargo fetch"
164 fi
165 fi
166 if [ -n "$file" ]; then
167 before="$(sha1sum "$file")"
168 fi
169 _runJj "$@"
170 wrapped_status=$?
171 if [[ $wrapped_status -ne 0 ]]; then
172 return $wrapped_status
173 fi
174 if [ -n "$file" ] && [ -e "$file" ]; then
175 after="$(sha1sum "$file")"
176 if [ "$after" != "$before" ]; then
177 eval "$cmd"
178 return $?
179 fi
180 fi
181 return $wrapped_status
182}
183
184function jj() {
185 if [[ "$1" = "new" && "$#" -eq 2 && "$2" != *@* && "$2" != -* ]]; then
186 if ! command jj log -r "$2" --no-graph -T "" >/dev/null 2>&1 && command jj log -r "$2@origin" --no-graph -T "" >/dev/null 2>&1; then
187 wrapWithAutoInstall new "$2@origin"
188 else
189 wrapWithAutoInstall "$@"
190 fi
191 elif [[ "$*" = "git push"* ]] && [[ "$*" != *"--dry-run"* ]]; then
192 # confirm before pushing, but only when the dry-run has something to push
193 local dry dry_status
194 dry="$(command jj "$@" --dry-run 2>&1)"
195 dry_status=$?
196 print -r -- "$dry"
197 if [[ $dry_status -ne 0 ]]; then
198 return $dry_status
199 fi
200 if [[ "$dry" = *"No bookmarks/tags found in the default push revset"* && "$dry" = *"Nothing changed."* && -n "$(command jj log -r '@ & ~empty()' --no-graph -T change_id 2>/dev/null)" ]]; then
201 local answer
202 printf "No bookmark on @; move previous bookmark to @ and push? [y/N] "
203 read -r answer
204 case "$answer" in
205 y|Y|yes|YES)
206 bup || return $?
207 dry="$(command jj "$@" --dry-run 2>&1)"
208 dry_status=$?
209 print -r -- "$dry"
210 if [[ $dry_status -ne 0 ]]; then
211 return $dry_status
212 fi
213 if [[ "$dry" != *"Nothing changed."* ]]; then
214 _runJj "$@"
215 return $?
216 fi
217 ;;
218 esac
219 fi
220 if [[ "$dry" != *"Nothing changed."* ]]; then
221 printf "Press any key to continue... "
222 read -r
223 _runJj "$@"
224 return $?
225 fi
226 return 0
227 elif [[ "$1" = "undo" || "$1" = "redo" ]]; then
228 _runJj "$@"
229 else
230 # auto-install deps when switching commits
231 wrapWithAutoInstall "$@"
232 fi
233}
234
235function bup() {
236 if [[ -z "$(command jj log -r @ -T description --no-graph 2>/dev/null)" ]]; then
237 command jj desc -m 'chore: follow-up changes'
238 fi
239 command jj b m --from 'heads(::@- & bookmarks()) ~ (trunk() | bookmarks(glob:"deployment*"))' --to '@'
240}