]> git.sev.monster Git - dotfiles.git/blame_incremental - etc/zsh/.zshrc
vimrc: fix modeline aucmd
[dotfiles.git] / etc / zsh / .zshrc
... / ...
CommitLineData
1### options
2setopts=(
3 ## 16.2.1 Changing Directories
4 AUTO_CD CDABLE_VARS
5 ## 16.2.2 Completion
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
9 NUMERIC_GLOB_SORT
10 ## 16.2.4 History
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 HIST_FCNTL_LOCK HIST_IGNORE_DUPS HIST_IGNORE_SPACE HIST_LEX_WORDS
14 HIST_NO_STORE HIST_REDUCE_BLANKS NO_HIST_SAVE_BY_COPY SHARE_HISTORY
15 ## 16.2.6 Input/Output
16 NO_CLOBBER CLOBBER_EMPTY CORRECT_ALL INTERACTIVE_COMMENTS
17 HASH_EXECUTABLES_ONLY
18 ## 16.2.7 Job Control
19 AUTO_CONTINUE LONG_LIST_JOBS
20 ## 16.2.12 Zle
21 NO_BEEP
22)
23setopt $setopts
24unset setopts
25
26### exports
27## common
28export EDITOR=${$(whence -p nvim vim vi micro nano emacs)[(f)1]}
29export PAGER=${$(whence -p less micro nano more)[(f)1]:s/micro/& -readonly true -multiopen tab/:s/nano/& --view}
30## grep
31# XXX: deprecated in GNU
32export GREP_OPTIONS=--color=auto
33## histfile
34export HISTFILE=~/.histfile
35export HISTSIZE=10000
36export SAVEHIST=$HISTSIZE
37## python
38export PYTHONSTARTUP=${XDG_CONFIG_HOME:-~/.config}/pythonrc
39## vim
40export VIMINIT='let$MYVIMRC=($XDG_CONFIG_HOME??($HOME."/.config"))."/vim/.vimrc"|execute"source"$MYVIMRC'
41
42### imports
43autoload -Uz zmv
44autoload -Uz zmathfunc && zmathfunc
45
46## vcs
47zstyle ':vcs_info:*' enable git
48#zstyle ':vcs_info:git*' check-for-changes true #too slow
49zstyle ':vcs_info:git*:dotfiles' check-for-changes true
50zstyle ':vcs_info:git*' check-for-staged-changes true
51autoload -Uz vcs_info
52
53## compinit
54zstyle ':completion:*' auto-description '[arg] %d'
55zstyle ':completion:*' expand suffix
56zstyle ':completion:*' format '# %d'
57zstyle ':completion:*' group-name ''
58zstyle ':completion:*' ignore-parents parent
59zstyle ':completion:*' insert-unambiguous false
60zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
61zstyle ':completion:*' list-prompt '%B%i%b'
62zstyle ':completion:*' list-suffixes true
63zstyle ':completion:*' matcher-list '' 'm:{[:lower:]}={[:upper:]}' 'm:{[:lower:][:upper:]}={[:upper:][:lower:]} r:|[._-]=* r:|=*' 'm:{[:lower:][:upper:]}={[:upper:][:lower:]} l:|=* r:|=*'
64zstyle ':completion:*' menu select=1
65zstyle ':completion:*' original false
66zstyle ':completion:*' select-prompt '%B%l%b'
67zstyle ':completion:*' verbose true
68autoload -Uz compinit
69cache=${XDG_CACHE_HOME:-~/.cache}/zsh
70[[ -d $cache ]] || mkdir -p $cache
71compinit -d $cache/.zcompdump
72unset cache
73
74### keys
75## set up zkbd-style key array
76if [[ ! -v _sev_force_zkbd && ( -v terminfo || -v termcap ) ]] {
77 # use application (keypad transmit) mode if the terminal supports it
78 # NOTE: we have to do this because termcap/terminfo keys are usually
79 # defined in application mode. terminals that do not define these
80 # capabilities are assumed to always be in application mode.
81 if [[ ( -v terminfo[smkx] && -v terminfo[rmkx] ) ||
82 ( -v termcap[ks] && -v terminfo[ke] ) ]] {
83 autoload -Uz add-zle-hook-widget
84 function _enter-application-mode {
85 [[ -v terminfo[smkx] ]] && echoti smkx || echotc ks
86 }
87 add-zle-hook-widget line-init _enter-application-mode
88 function _exit-application-mode {
89 [[ -v terminfo[rmkx] ]] && echoti rmkx || echotc ke
90 }
91 add-zle-hook-widget line-finish _exit-application-mode
92 trap _exit-application-mode EXIT
93 }
94 # pull keys from terminfo/termcap
95 # TODO: Menu and more Shift- modifiers
96 typeset -gA key
97 typeset -lA newkey
98 if [[ -v terminfo ]] {
99 src=terminfo
100 newkey=(F1 kf1 F2 kf2 F3 kf3 F4 kf4 F5 kf5 F6 kf6 F7 kf7 F8 kf8 F9 kf9
101 F10 kf10 F11 kf11 F12 kf12
102 Backspace kbs
103 Shift-Tab kcbt
104 Insert kich1
105 Home khome
106 PageUp kpp
107 Delete kdch1
108 End kend
109 PageDown knp
110 Up kcuu1
111 Down kcud1
112 Left kcub1
113 Right kcuf1
114 )
115 } elif [[ -v termcap ]] {
116 src=termcap
117 newkey=(F1 k1 F2 k2 F3 k3 F4 k4 F5 k5 F6 k6 F7 k7 F8 k8 F9 k9
118 F10 k\; F11 F1 F12 F2
119 Backspace kb
120 Shift-Tab kB
121 Insert kI
122 Home kh
123 PageUp kP
124 Delete kD
125 End @7
126 PageDown kN
127 Up ku
128 Down kd
129 Left kl
130 Right kr
131 )
132 }
133 for k v (${(kv)newkey}) {
134 key[$k]=${${(P)src}[$v]}
135 }
136 unset k v src newkey
137} else {
138 # use zkbd if termcap/terminfo unavailable
139 function find_keymap {
140 for f in ${ZDOTDIR:-~}/.zkbd/$TERM{-${DISPLAY:-$VENDOR-$OSTYPE},}
141 [[ -f $f ]] && keymap=$f && break
142 }
143 find_keymap
144 if [[ -z $keymap ]] {
145 if read -q "?Can't read terminfo. Add new zkbd keymap? [y/N]"; then
146 echo
147 autoload -Uz zkbd && zkbd
148 unfunction zkbd
149 find_keymap
150 fi
151 echo
152 }
153 if [[ -n $keymap ]] {
154 source $keymap
155 } else {
156 echo -E "Failed to source keymap file $keymap" >&2
157 }
158 unfunction find_keymap; unset keymap
159}
160
161## load history search
162autoload -Uz up-line-or-beginning-search down-line-or-beginning-search
163zle -N up-line-or-beginning-search
164zle -N down-line-or-beginning-search
165
166## bind keys in both viins and vicmd modes
167# NOTE: cursor keys are bound to normal/raw/nontransmit mode strings by
168# default, and keys like Home and End are not bound at all, so we rebind
169# everything to cover all scenarios
170typeset -A a
171a=(
172 #key viins vicmd
173 Backspace 'backward-delete-char vi-backward-char'
174 Insert 'overwrite-mode vi-insert'
175 Home 'beginning-of-line'
176 PageUp 'up-history -'
177 Delete 'delete-char'
178 End 'end-of-line'
179 PageDown 'down-history -'
180 Up 'up-line-or-beginning-search vi-up-line-or-history'
181 Down 'down-line-or-beginning-search vi-down-line-or-history'
182 Left 'backward-char'
183 Right 'forward-char'
184)
185for k v (${(kv)a}) {
186 k=$key[$k]
187 if [[ -z $k ]] { continue }
188 v=($=v)
189 bindkey -- $k $v[1]
190 if [[ $v[2] == - ]] {
191 # copy viins to vicmd verbatim
192 bindkey -a -- $k $v[1]
193 } elif (( $#v != 1 )) {
194 # set vicmd to any other value
195 bindkey -a -- $k $v[2]
196 } else {
197 # copy viins to vicmd and prepend vi- to it
198 bindkey -a -- $k vi-$v[1]
199 }
200}
201unset a k v
202
203## fzf
204# bash-style reverse-search-history (i.e. reverse-i-search)
205if [[ -v commands[fzf] ]] {
206 function _history-incremental-pattern-search-fzf {
207 l=(${(f)"$(fc -li -1 0 | fzf -e -m -n 1 +s --preview-window=hidden ${BUFFER:+-q $BUFFER})"})
208 l=$(for x ("${l[@]}") { echo ${${=x}:3}; })
209 BUFFER="$l"
210 }
211 zle -N _history-incremental-pattern-search-fzf
212 bindkey '^R' _history-incremental-pattern-search-fzf
213} else {
214 bindkey '^R' history-incremental-pattern-search-backward
215}
216
217### aliases
218## builtins
219alias rehash='_sev_setpath; rehash'
220## utils
221alias h='fc -l -25'
222alias j='jobs -l'
223alias l='ls -AF'
224if [[ "$OSTYPE" =~ '^(free|net)bsd' ]] {
225 alias ll='ls -lAFho'
226} else {
227 alias ll='ls -lAFh'
228}
229alias p=\$PAGER
230alias e=\$EDITOR
231alias se=sudoedit
232alias syncwatch='sync & watch -d grep -Fe Dirty: -e Writeback: /proc/meminfo'
233if [[ -v commands[grep] ]] {
234 [[ -v commands[fgrep] ]] || alias fgrep='grep -F'
235 [[ -v commands[egrep] ]] || alias fgrep='grep -E'
236}
237for x (cat cmp diff grep test update) {
238 [[ -v commands[zutils-z$x] ]] || alias z$x=zutils-z$x
239}
240# be paranoid
241alias cp='cp -ip'
242alias mv='mv -i'
243# zsh zmv with noglob wildcards
244alias zm='noglob zmv -WiM'
245alias zc='noglob zmv -WiC'
246alias zl='noglob zmv -WiL'
247alias sm='noglob zmv -Wip"sudo mv"'
248alias sc='noglob zmv -Wip"sudo cp"'
249alias sl='noglob zmv -Wip"sudo ln"'
250if [[ "$OSTYPE" =~ '^freebsd' ]] {
251 # don't confirm if only a few files are deleted
252 alias rm='rm -I'
253} else {
254 # TODO: similar behavior for non-freebsd, or impliment in zsh
255 alias rm='rm -i'
256}
257[[ -v commands[trash-put] ]] && alias t=trash-put
258# ps
259if [[ -v commands[pstree] && $commands[pstree]:A:t != busybox ]] {
260 # use pstree, but NOT busybox pstree because it kinda sucks
261 ps='pstree -wg3'
262} elif [[ "$OSTYPE" =~ '^freebsd' ]] {
263 ps='ps -aSdfxwwouser=USR -ogroup=GRP -opid,nice=NI \
264 -o%cpu,%mem,tty,stat,start=START -oetime,command'
265} elif [[ $commands[ps]:A:t == busybox ]] {
266 # busybox compatible
267 ps="ps -eouser='USR ' -ogroup='GRP ' \
268 -opid=' PID' -onice=' NI' -ovsz=' MEM' \
269 -otty,stat,etime,comm"
270} else {
271 # XXX: untested, posix
272 # TODO: support gnu ps
273 ps='ps -eouser=USR -ogroup=GRP -opid,nice=NI \
274 -opcpu=CPU -ovsz=MEM -otty,stat,etime,comm'
275}
276if [[ "$(basename "$PAGER")" = "less" ]] {
277 ps="$ps | less -S"
278} else {
279 ps="$ps | \"${PAGER:-more}\""
280}
281alias pa=$ps
282alias spa="sudo $ps"
283unset ps
284## py venv
285alias va='source bin/activate'
286alias vd=deactivate
287alias vu="python3 -mvenv --upgrade"
288alias svu="sudo python3 -mvenv --upgrade"
289## git
290alias g=git
291alias gd='git diff'
292alias gdh='git diff HEAD'
293alias gds='git diff --staged'
294alias ga='git add'
295alias ga.='git add .'
296alias gai='git add -i'
297alias gap='git add -p'
298alias gc='git commit'
299alias gca='git commit --amend'
300alias gp='git push'
301alias gu='git pull'
302alias gl='git log'
303alias gt='git tree' # from gitconfig
304alias gsh='git show'
305alias gst='git status'
306alias gs='git stash'
307alias gsp='git stash pop'
308## cd/zoxide
309function up {
310 \cd $(printf '../%.0s' {1..${1:-1}})
311}
312alias u=up
313if [[ -v commands[zoxide] ]] {
314 # https://github.com/ajeetdsouza/zoxide/issues/513
315 eval "${$(zoxide init zsh):s#_files -/#_cd#}"
316 alias cd=z
317}
318alias cd..=up
319## dotfiles
320alias dfu='function {
321 pushd -q ${$(echo -E - ~/.zshenv):P:h:h}
322 git pull &&
323 git submodule init &&
324 git submodule sync &&
325 git submodule update
326 popd -q
327}'
328## nocorrect
329# zsh doesnt really handle sudo very well, so ignore it
330alias sudo='nocorrect sudo'
331## docker compose
332alias dcp='sudo docker compose pull'
333alias dcu='sudo docker compose up -d'
334alias dcr='sudo docker compose restart'
335alias dcl='sudo docker compose logs -f'
336
337### hooks
338autoload -Uz add-zsh-hook
339typeset -gi _sev_exectime
340function sev_preexec {
341 # change terminal title to show command
342 print -n "\e]2;$(print -P '%#')${SSH_CLIENT+$USER@$HOST:}$1\e\\"
343 # save last exec time for bell
344 # XXX: does not run for blank cmdline
345 _sev_exectime=$SECONDS
346 # update gpg forward, to always have unique filename and avoid clashes
347 if [[ -v _GNUPG_SOCK_DEST_EXT ]] {
348 export _GNUPG_SOCK_DEST_EXT=$(date +%s).$RANDOM
349 export _GNUPG_SOCK_DEST=$_GNUPG_SOCK_DEST_BASE.$_GNUPG_SOCK_DEST_EXT
350 }
351}
352add-zsh-hook preexec sev_preexec
353function sev_precmd {
354 # change terminal title
355 # TODO: update and send BEL when job status changes
356 print -Pn "\e]2;%(1j,%j,)%#${SSH_CLIENT+$USER@$HOST:}%~\e\\"
357 # bell if exec takes 5s
358 if (( SECONDS - _sev_exectime >= 5 )) print "\a"
359 # we could update vcs_info here, but let prompt take care of it
360 # if it doesn't use vcs, it can be ignored safely
361}
362add-zsh-hook precmd sev_precmd
363function sev_chpwd {
364 # echo dir on cwd change
365 ls -AF
366}
367add-zsh-hook chpwd sev_chpwd
368
369### system-specific configs and aliases
370case $OSTYPE; in
371 freebsd*)
372 ## colors
373 export CLICOLOR=
374 export LS_COLORS='di=34:ln=35:so=32:pi=33:ex=31:bd=46;34:cd=43;34:su=41;30:sg=46;30:tw=42;30:ow=43;30'
375
376 ## sound
377 function s { sysctl hw.snd.default_unit${1:+\=$1} }
378 alias vol mixer
379
380 ## install port dependencies from pkg (like pkgsrc `bmake bin-install')
381 # XXX: should probably use package-depends where possible, breaks when
382 # port name is different to package name
383 # (eg. graphics/sdl20 == sdl2, devel/glib20 == glib2, etc)
384 function portpkg {
385 case "$1" {
386 build|run)
387 sudo pkg install -AU $(make ${1}-depends-list |
388 sed 's_/usr/ports/_ _' | tr -d '\n')
389 ;;
390 *) echo "Usage: \`portpkg <build|run>' in a port directory"
391 return 1;;
392 }
393 };;
394 netbsd)
395 ## sound
396 function s {
397 if [[ -z "$1" ]] {
398 ll /dev/mixer /dev/sound /dev/audio
399 return
400 }
401 for x in mixer sound audio; do
402 ln -sf /dev/$x"$1" /dev/$x
403 done
404 }
405 function vol {
406 if [[ -z "$1" ]] {
407 for x in $(mixerctl -a | grep 'outputs\.master'); do
408 echo -E - $x
409 done
410 return
411 }
412 mixerctl -w outputs.master"$2"="$1"
413 };;
414 *)
415 ## sound
416 # TODO: test alsa/oss/sndio/portaudio/pulse/pipewire in order of importance
417 function s {}
418 function vol {}
419esac
420
421### prompt
422autoload -Uz promptinit && promptinit
423prompt arrows
424
425### plugins
426load-plugins zshrc
427
428### load site-specific
429load-site-dotfile zshrc
This page took 0.03153 seconds and 4 git commands to generate.