]> git.sev.monster Git - dotfiles.git/blob - etc/zsh/.zshrc
1972179b845da5c9729087918069902b03cb2f34
[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 -E "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 ga.='git add .'
255 alias gc='git commit'
256 alias gca='git commit --amend'
257 alias gp='git push'
258 alias gu='git pull'
259 ## cd/zoxide
260 function up {
261     \cd $(printf '../%.0s' {1..${1:-1}})
262 }
263 alias u=up
264 if [[ -v commands[zoxide] ]] {
265     # https://github.com/ajeetdsouza/zoxide/issues/513
266     eval "${$(zoxide init zsh):s#_files -/#_cd#}"
267     alias cd=z
268 }
269 alias cd..=up
270 ## dotfiles
271 alias dfu='d=${$(echo -E - ~/.zshenv):P:h:h};GIT_DIR=$d/.git GIT_WORK_TREE=$d {
272   git pull &&
273   git submodules init &&
274   git submodules sync &&
275   git submodules update
276 }'
277 >>>>>>> Stashed changes
278
279 ### hooks
280 autoload -Uz add-zsh-hook
281 _sev_exectime=
282 function sev_preexec {
283     # change terminal title to show command
284     print -n "\e]2;$(print -P '%#')${SSH_CLIENT+$USER@$HOST:}$1\e\\"
285     # save last exec time for bell
286     # XXX: does not run for blank cmdline
287     _sev_exectime=$SECONDS
288     # update gpg forward, to always have unique filename and avoid clashes
289     if [[ -v _GNUPG_SOCK_DEST_EXT ]] {
290         export _GNUPG_SOCK_DEST_EXT=$(date +%s).$RANDOM
291         export _GNUPG_SOCK_DEST=$_GNUPG_SOCK_DEST_BASE.$_GNUPG_SOCK_DEST_EXT
292     }
293 }
294 add-zsh-hook preexec sev_preexec
295 function sev_precmd {
296     # change terminal title
297     # TODO: update and send BEL when job status changes
298     print -Pn "\e]2;%(1j,%j,)%#${SSH_CLIENT+$USER@$HOST:}%~\e\\"
299     # bell if exec takes 5s
300     if (( SECONDS - _sev_exectime >= 5 )) print "\a"
301     # we could update vcs_info here, but let prompt take care of it
302     # if it doesn't use vcs, it can be ignored safely
303 }
304 add-zsh-hook precmd sev_precmd
305 function sev_chpwd {
306     # echo dir on cwd change
307     ls -AF
308 }
309 add-zsh-hook chpwd sev_chpwd
310
311 ### system-specific configs and aliases
312 case $OSTYPE; in
313     freebsd*)
314         ## colors
315         export CLICOLOR=
316         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'
317
318         ## sound
319         function s { sysctl hw.snd.default_unit${1:+\=$1} }
320         alias vol mixer
321
322         ## install port dependencies from pkg (like pkgsrc `bmake bin-install')
323         # XXX: should probably use package-depends where possible, breaks when
324         #      port name is different to package name
325         #      (eg. graphics/sdl20 == sdl2, devel/glib20 == glib2, etc)
326         function portpkg {
327             case "$1" {
328             build|run)
329                 sudo pkg install -AU $(make ${1}-depends-list |
330                            sed 's_/usr/ports/_ _' | tr -d '\n')
331                 ;;
332             *)  echo "Usage: \`portpkg <build|run>' in a port directory"
333                 return 1;;
334             }
335         };;
336     netbsd)
337         ## sound
338         function s {
339             if [[ -z "$1" ]] {
340                 ll /dev/mixer /dev/sound /dev/audio
341                 return
342             }
343             for x in mixer sound audio; do
344                 ln -sf /dev/$x"$1" /dev/$x
345             done
346         }
347         function vol {
348             if [[ -z "$1" ]] {
349                 for x in $(mixerctl -a | grep 'outputs\.master'); do
350                     echo -E - $x
351                 done
352                 return
353             }
354             mixerctl -w outputs.master"$2"="$1"
355         };;
356     *)
357         ## sound
358         # TODO: test alsa/oss/sndio/portaudio/pulse/pipewire in order of importance
359         function s {}
360         function vol {}
361 esac
362
363 ### prompt
364 autoload -Uz promptinit && promptinit
365 prompt arrows
366
367 ### load site-specific
368 load-site-dotfile zshrc
This page took 0.04299 seconds and 2 git commands to generate.