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