-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy path.zshrc
251 lines (206 loc) · 7.46 KB
/
.zshrc
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
# Load oh-my-zsh if available
# git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh
# Quick abbreviations for very common redirections.
alias -g ,1='2>&1'
alias -g ,2='2>/dev/null'
# Ignore special characters like "#" and ";" when running the "ci" command.
ci-helper () {
local message="$history[$(print -P %h)]"
message="$(echo "$message" | sed 's/ci //')"
local length="${#message}"
if (( length > 50 ))
then
echo 'Error: message has more than 50 characters ^==='
return 1
fi
if [ -d .git/refs/jj ]
then
jj describe -m "$message"
else
git ci -m "$message" .
fi
}
alias ci='ci-helper #'
# Custom completions.
compdef s=ssh
# Activate virtual environments automatically when $PWD changes.
__compute_environment_slug () {
local relative="${PWD#$HOME}" # Remove any $HOME prefix
if [ "$relative" = "$PWD" ] ;then return 1 ;fi # Ignore dirs outside $HOME.
if [ "$relative" = "" ] ;then return 1 ;fi # Ignore $HOME itself.
echo "${${relative#/}//\//-}" # "a/b/c" -> "a-b-c"
}
__detect_cd_and_possibly_activate_environment () {
if [ "$PWD" = "$OPWD" ]
then return
fi
OPWD="$PWD"
local slug
if slug="$(__compute_environment_slug)"
then
if [ "$slug" != "$ENV_SLUG" -a -d ~/.v/"$slug" ]
then
local PROMPT # protect from "activate", "deactivate"
if [ -n "$VIRTUAL_ENV" ]
then
deactivate
elif [ -n "$CONDA_DEFAULT_ENV" ]
then
source deactivate
fi
source ~/.v/"$slug"/bin/activate ~/.v/"$slug"
ENV_PATH="$PWD"
ENV_SLUG="$slug"
fi
fi
prompt_cwd=$PWD
if [ -n "$ENV_SLUG" ] && [[ $PWD/ == ${ENV_PATH}/* ]]
then
prompt_cwd=${PWD#$ENV_PATH} # "~/project/a/b" -> "/a/b"
prompt_cwd=${prompt_cwd#/} # "/a/b" -> "a/b"
prompt_cwd=${prompt_cwd:-.} # empty string -> "."
else
prompt_cwd="$(print -P '%~')"
fi
}
,v () {
local slug python version
if ! slug=$(__compute_environment_slug)
then
echo "Error: must be in a directory beneath your home directory" >&2
return 1
fi
if [ -f ".python-version" ]
then
uv venv ~/.v/"$slug"
else
if [ -z "$1" ]
then
pyenv versions | grep -v ' 3'
echo
uv python list
return 1
fi
version="$1"
mkdir -p ~/.v
if [[ "$version" =~ '3.' ]]
then
uv venv --python "$@" ~/.v/"$slug"
else
shift
python="$(PYENV_VERSION="$version" pyenv which python)"
python2 ~/local/src/virtualenv/virtualenv.py -p "$python" "$@" \
~/.v/"$slug"
fi
fi &&
unset OPWD &&
__detect_cd_and_possibly_activate_environment
}
# Build a pretty prompt.
if [ -z "$TERM" -o "$TERM" = "dumb" ]
then
# Avoid "^[[?2004h" after each prompt when running inside of Emacs.
unset zle_bracketed_paste
else
autoload -Uz bracketed-paste-magic
zle -N bracketed-paste bracketed-paste-magic
autoload -Uz url-quote-magic
zle -N self-insert url-quote-magic
zle_highlight=(default:fg=0,bg=7,bold)
if [ -z "$SSH_TTY" ]
then
PS1=$'%B%F{white}%(?.%K{green} .%K{red}%?) %(?.%F{green}.%F{red})%k\ue0b0%f '
else
PS1="${HOST:-${HOSTNAME}}"
# Keep only the first component of a fully-qualified hostname.
PS1="${PS1%%.*}"
# TODO: make this fancier? or pop remote case out and simplify,
# since who knows where I might be SSH'ing from, maybe no Unicode?
fi
RPROMPT=$'%B%(1V.%F{%1v}\ue0b2%K{%1v}%F{white} \ue0a0%2v .)%(3V.%F{white}%K{cyan} %3v .)%F{white}%K{black} %18<…<%4v '
precmd() {
local color rev root status_lines
rehash
__detect_cd_and_possibly_activate_environment
root=$(git rev-parse --show-toplevel 2>/dev/null)
if [ -n "$root" ]
then
if [ -d .git/refs/jj ]
then
status_lines="$(jj log -r '(remote_bookmarks()..@)-' \
--no-graph -T 'remote_bookmarks')"
rev=$(echo $status_lines | grep -oP '(\w+)(?=@origin)')
if jj log -T builtin_log_oneline -r 'remote_bookmarks()..' \
--no-graph | grep -qv '(empty)'
then
color=red
else
color=green
fi
elif [ -f "$root/.git/no-prompt" ]
then
# Too expensive to run "status" each time.
rev=off
else
rev="$(GIT_OPTIONAL_LOCKS=0 git rev-parse --abbrev-ref HEAD)"
status_lines="$(GIT_OPTIONAL_LOCKS=0 git status --porcelain)"
status_lines=":${status_lines//
/:}" # delimit the lines with colons instead
if [[ "$status_lines" =~ ':[^?][^?]' ]]
then color=red
elif [ "$status_lines" = ':' ]
then color=green
else color=yellow
fi
fi
fi
psvar=("$color" "$rev" "$ENV_SLUG" "$prompt_cwd")
}
fi
# Automatically source ,p instead of running it in in a separate shell.
alias ,p="source ~/bin/,p"
# Moving forward by one word should land at the end of the next word,
# not at its beginning.
bindkey "\eF" emacs-forward-word
bindkey "\ef" emacs-forward-word
# An easy keyboard shortcut to edit a long complicated command in my editor.
autoload -z edit-command-line
zle -N edit-command-line
bindkey "^Xe" edit-command-line
# And forward-word and backward-word should not consider punctuation to
# be part of a word.
WORDCHARS=
# Prevent "!" characters from being special on the command line, since I
# always use Ctrl-R searching and Emacs command-line editing if I want
# to adjust and re-run a previous command.
unsetopt bang_hist
# Prevent duplicate commands from filling history.
setopt hist_ignore_dups
# Print the duration of the most recent command, to avoid my habit of
# Control-C'ing a command once I see that it's going to take several
# seconds, and re-running it with `time`.
,elapsed () {
fc -l -D -1 | awk '{print "The",$3,"command took",$2,"to run"}'
}
# Don't complain if I paste part of a shell script into the command
# line, and some lines start with '#'. They are comments! I'm not
# trying to run the program '#'!
setopt interactivecomments
# If TAB can complete at least a partial word, then zsh by default is
# quite lazy and makes *me* hit TAB again to then see the options that
# remain following the characters it fills in. With this option, it will
# always respond to my TAB by showing the list of completions, whether
# there were a few characters that it went ahead and filled in, or not.
# I noticed this when using my new "clone" command, because typing
# "clone <TAB>" was filling in the common prefix "[email protected]:name/"
# and then making me hit TAB all over again to see the repository names.
unsetopt list_ambiguous
# Don't ring the terminal bell during completion.
setopt no_beep
# During completion, allow moving through the menu with arrow keys.
zstyle ':completion:*' menu select
# Install my other customizations.
source ~/.bashrc
# This needs to be set after ~/.bashrc and ~/.bashenv are run, because
# setting $TERMINFO_DIRS resets its value to 1.
ZLE_RPROMPT_INDENT=0