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