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