3 ## 16.2.1 Changing Directories
6 COMPLETE_IN_WORD GLOB_COMPLETE REC_EXACT
7 ## 16.2.3 Expansion and Globbing
8 EXTENDED_GLOB GLOB_DOTS GLOB_STAR_SHORT MAGIC_EQUAL_SUBST MARK_DIRS
11 # NOTE: NO_HIST_SAVE_BY_COPY to allow saving histfile if updating another
12 # user's histfile. this is for compatibility with zsu.
13 EXTENDED_HISTORY HIST_FCNTL_LOCK HIST_IGNORE_ALL_DUPS HIST_IGNORE_DUPS
14 HIST_IGNORE_SPACE HIST_LEX_WORDS HIST_NO_STORE HIST_REDUCE_BLANKS
15 NO_HIST_SAVE_BY_COPY HIST_SAVE_NO_DUPS SHARE_HISTORY
16 ## 16.2.6 Input/Output
17 NO_CLOBBER CLOBBER_EMPTY CORRECT_ALL INTERACTIVE_COMMENTS
20 AUTO_CONTINUE LONG_LIST_JOBS
29 export EDITOR=${$(whence -p nvim vim vi micro nano emacs)[(f)1]}
30 export PAGER=${$(whence -p less micro nano more)[(f)1]:s/micro/& -readonly true -multiopen tab/:s/nano/& --view}
32 # XXX: deprecated in GNU
33 export GREP_OPTIONS=--color=auto
35 export HISTFILE=~/.histfile
37 export SAVEHIST=$HISTSIZE
39 export PYTHONSTARTUP=${XDG_CONFIG_HOME:-~/.config}/pythonrc
41 export VIMINIT='let$MYVIMRC=($XDG_CONFIG_HOME??($HOME."/.config"))."/vim/.vimrc"|execute"source"$MYVIMRC'
45 autoload -Uz zmathfunc && zmathfunc
48 zstyle ':vcs_info:*' enable git
49 #zstyle ':vcs_info:git*' check-for-changes true #too slow
50 zstyle ':vcs_info:git*:dotfiles' check-for-changes true
51 zstyle ':vcs_info:git*' check-for-staged-changes true
55 zstyle ':completion:*' auto-description '[arg] %d'
56 zstyle ':completion:*' expand suffix
57 zstyle ':completion:*' format '# %d'
58 zstyle ':completion:*' group-name ''
59 zstyle ':completion:*' ignore-parents parent
60 zstyle ':completion:*' insert-unambiguous false
61 zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
62 zstyle ':completion:*' list-prompt '%B%i%b'
63 zstyle ':completion:*' list-suffixes true
64 zstyle ':completion:*' matcher-list '' 'm:{[:lower:]}={[:upper:]}' 'm:{[:lower:][:upper:]}={[:upper:][:lower:]} r:|[._-]=* r:|=*' 'm:{[:lower:][:upper:]}={[:upper:][:lower:]} l:|=* r:|=*'
65 zstyle ':completion:*' menu select=1
66 zstyle ':completion:*' original false
67 zstyle ':completion:*' select-prompt '%B%l%b'
68 zstyle ':completion:*' verbose true
70 cache=${XDG_CACHE_HOME:-~/.cache}/zsh
71 [[ -d $cache ]] || mkdir -p $cache
72 compinit -d $cache/.zcompdump
76 ## set up zkbd-style key array
77 if [[ ! -v _sev_force_zkbd && ( -v terminfo || -v termcap ) ]] {
78 # use application (keypad transmit) mode if the terminal supports it
79 # NOTE: we have to do this because termcap/terminfo keys are usually
80 # defined in application mode. terminals that do not define these
81 # capabilities are assumed to always be in application mode.
82 if [[ ( -v terminfo[smkx] && -v terminfo[rmkx] ) ||
83 ( -v termcap[ks] && -v terminfo[ke] ) ]] {
84 autoload -Uz add-zle-hook-widget
85 function _enter-application-mode {
86 [[ -v terminfo[smkx] ]] && echoti smkx || echotc ks
88 add-zle-hook-widget line-init _enter-application-mode
89 function _exit-application-mode {
90 [[ -v terminfo[rmkx] ]] && echoti rmkx || echotc ke
92 add-zle-hook-widget line-finish _exit-application-mode
93 trap _exit-application-mode EXIT
95 # pull keys from terminfo/termcap
96 # TODO: Menu and more Shift- modifiers
99 if [[ -v terminfo ]] {
101 newkey=(F1 kf1 F2 kf2 F3 kf3 F4 kf4 F5 kf5 F6 kf6 F7 kf7 F8 kf8 F9 kf9
102 F10 kf10 F11 kf11 F12 kf12
116 } elif [[ -v termcap ]] {
118 newkey=(F1 k1 F2 k2 F3 k3 F4 k4 F5 k5 F6 k6 F7 k7 F8 k8 F9 k9
119 F10 k\; F11 F1 F12 F2
134 for k v (${(kv)newkey}) {
135 key[$k]=${${(P)src}[$v]}
139 # use zkbd if termcap/terminfo unavailable
140 function find_keymap {
141 for f in ${ZDOTDIR:-~}/.zkbd/$TERM{-${DISPLAY:-$VENDOR-$OSTYPE},}
142 [[ -f $f ]] && keymap=$f && break
145 if [[ -z $keymap ]] {
146 if {read -q "?Can't read terminfo. Add new zkbd keymap? [y/N]"} {
149 autoload -Uz zkbd && zkbd
158 if [[ -n $keymap ]] {
161 echo -E "Failed to source keymap file $keymap" >&2
163 unfunction find_keymap; unset keymap
166 ## load history search
167 autoload -Uz up-line-or-beginning-search down-line-or-beginning-search
168 zle -N up-line-or-beginning-search
169 zle -N down-line-or-beginning-search
171 ## bind keys in both viins and vicmd modes
172 # NOTE: cursor keys are bound to normal/raw/nontransmit mode strings by
173 # default, and keys like Home and End are not bound at all, so we rebind
174 # everything to cover all scenarios
178 Backspace 'backward-delete-char vi-backward-char'
179 Insert 'overwrite-mode vi-insert'
180 Home 'beginning-of-line'
181 PageUp 'up-history -'
184 PageDown 'down-history -'
185 Up 'up-line-or-beginning-search vi-up-line-or-history'
186 Down 'down-line-or-beginning-search vi-down-line-or-history'
192 if [[ -z $k ]] { continue }
195 if [[ $v[2] == - ]] {
196 # copy viins to vicmd verbatim
197 bindkey -a -- $k $v[1]
198 } elif (( $#v != 1 )) {
199 # set vicmd to any other value
200 bindkey -a -- $k $v[2]
202 # copy viins to vicmd and prepend vi- to it
203 bindkey -a -- $k vi-$v[1]
209 # bash-style reverse-search-history (i.e. reverse-i-search)
210 if [[ -v commands[fzf] ]] {
211 function _history-incremental-pattern-search-fzf {
213 # XXX: this shit is cursed and sometimes doesn't work
214 # TODO: remove doesn't work over newlines, fzf replaces them with \n,
215 # and sed of course hates newlines and would need to be massaged
216 # TODO: interactive history refresh... can't get zsh to load histfile:
217 # +reload(HISTFILE='"$h HISTSIZE=$HISTSIZE SAVEHIST=$SAVEHIST \$0 +Z -dfimc 'setopt EXTENDED_HISTORY;fc -R \$HISTFILE;$c' </dev/null 2>&1)" \
218 local c='fc -lt%F -1 0'
219 local h="'${HISTFILE//\'/\'\\\'\'}'"
220 local l=(${(f)"$($=c | fzf \
221 --scheme=history -e -n 1,3.. \
223 -m --bind 'ctrl-d:execute-silent(sed -i -f <(
224 sed -Ee '\''s/[$*.[\^/]/\\&/g;s~.*~/^\\(: [0-9]\\+:[0-9]\\+;\\)\\?&$/d~'\'' {+f3..}
226 --preview-window=hidden --height=20% \
227 --with-shell "${0:a} -dfc" \
228 ${BUFFER:+-q $BUFFER})"})
229 # XXX: this sucks, I hate this. no other way to flush internal history?
230 HISTFILE= HISTSIZE=0 fc -p $HISTFILE $HISTSIZE $SAVEHIST
231 l=$(for x ("${l[@]}") { echo ${${=x}:3}; })
235 zle -N _history-incremental-pattern-search-fzf
236 bindkey '^R' _history-incremental-pattern-search-fzf
238 bindkey '^R' history-incremental-pattern-search-backward
243 alias rehash='_sev_setpath; rehash'
248 if [[ "$OSTYPE" =~ '^(free|net)bsd' ]] {
256 alias syncwatch='sync & watch -d grep -Fe Dirty: -e Writeback: /proc/meminfo'
257 if [[ -v commands[grep] ]] {
258 [[ -v commands[fgrep] ]] || alias fgrep='grep -F'
259 [[ -v commands[egrep] ]] || alias fgrep='grep -E'
261 for x (cat cmp diff grep test update) {
262 [[ -v commands[zutils-z$x] ]] || alias z$x=zutils-z$x
267 # zsh zmv with noglob wildcards
268 alias zm='noglob zmv -WiM'
269 alias zc='noglob zmv -WiC'
270 alias zl='noglob zmv -WiL'
271 alias sm='noglob zmv -Wip"sudo mv"'
272 alias sc='noglob zmv -Wip"sudo cp"'
273 alias sl='noglob zmv -Wip"sudo ln"'
274 if [[ "$OSTYPE" =~ '^freebsd' ]] {
275 # don't confirm if only a few files are deleted
278 # TODO: similar behavior for non-freebsd, or impliment in zsh
281 [[ -v commands[trash-put] ]] && alias t=trash-put
283 if [[ -v commands[pstree] && $commands[pstree]:A:t != busybox ]] {
284 # use pstree, but NOT busybox pstree because it kinda sucks
286 } elif [[ "$OSTYPE" =~ '^freebsd' ]] {
287 ps='ps -aSdfxwwouser=USR -ogroup=GRP -opid,nice=NI \
288 -o%cpu,%mem,tty,stat,start=START -oetime,command'
289 } elif [[ $commands[ps]:A:t == busybox ]] {
291 ps="ps -eouser='USR ' -ogroup='GRP ' \
292 -opid=' PID' -onice=' NI' -ovsz=' MEM' \
293 -otty,stat,etime,comm"
295 # XXX: untested, posix
296 # TODO: support gnu ps
297 ps='ps -eouser=USR -ogroup=GRP -opid,nice=NI \
298 -opcpu=CPU -ovsz=MEM -otty,stat,etime,comm'
300 if [[ "$(basename "$PAGER")" = "less" ]] {
303 ps="$ps | \"${PAGER:-more}\""
309 alias va='source bin/activate'
311 alias vu="python3 -mvenv --upgrade"
312 alias svu="sudo python3 -mvenv --upgrade"
316 alias gdh='git diff HEAD'
317 alias gdp='git diff HEAD\^'
318 alias gds='git diff --staged'
320 alias ga.='git add .'
321 alias gai='git add -i'
322 alias gap='git add -p'
323 alias gc='git commit'
324 alias gca='git commit --amend'
328 alias gt='git tree' # from gitconfig
330 alias gshn='git show --name-status'
331 alias gst='git status'
332 alias gsts='git status --short'
334 alias gsp='git stash pop'
335 alias gsd='git stash drop'
336 alias gss='git stash show -p'
337 alias grc='git rebase --continue'
340 \cd $(printf '../%.0s' {1..${1:-1}})
343 if [[ -v commands[zoxide] ]] {
344 # https://github.com/ajeetdsouza/zoxide/issues/513
345 eval "${$(zoxide init zsh):s#_files -/#_cd#}"
351 alias dfu='function {
352 pushd -q ${$(echo -E - ~/.zshenv):P:h:h}
354 git submodule init &&
355 git submodule sync &&
360 # zsh doesnt really handle sudo very well, so ignore it
361 alias sudo='nocorrect sudo'
363 alias dcp='sudo docker compose pull'
364 alias dcu='sudo docker compose up -d'
365 alias dcr='sudo docker compose restart'
366 alias dcl='sudo docker compose logs -f'
369 autoload -Uz add-zsh-hook
370 typeset -gi _sev_exectime
371 function sev_preexec {
372 # change terminal title to show command
373 print -n "\e]2;$(print -P '%#')${SSH_CLIENT+$USER@$HOST:}$1\e\\"
374 # save last exec time for bell
375 # XXX: does not run for blank cmdline
376 _sev_exectime=$SECONDS
377 # update gpg forward, to always have unique filename and avoid clashes
378 if [[ -v _GNUPG_SOCK_DEST_EXT ]] {
379 export _GNUPG_SOCK_DEST_EXT=$(date +%s).$RANDOM
380 export _GNUPG_SOCK_DEST=$_GNUPG_SOCK_DEST_BASE.$_GNUPG_SOCK_DEST_EXT
383 add-zsh-hook preexec sev_preexec
384 function sev_precmd {
385 # change terminal title
386 # TODO: update and send BEL when job status changes
387 print -Pn "\e]2;%(1j,%j,)%#${SSH_CLIENT+$USER@$HOST:}%~\e\\"
388 # bell if exec takes 5s
389 if (( SECONDS - _sev_exectime >= 5 )) print "\a"
390 # we could update vcs_info here, but let prompt take care of it
391 # if it doesn't use vcs, it can be ignored safely
393 add-zsh-hook precmd sev_precmd
395 # echo dir on cwd change
398 add-zsh-hook chpwd sev_chpwd
401 autoload -Uz promptinit && promptinit
407 ### load site-specific
408 load-site-dotfile zshrc