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