]> git.sev.monster Git - dotfiles.git/blob - etc/zsh/.zshrc
30625bde7b2ae4a385b3f1b5f41594c84a61cb89
[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='let$MYVIMRC=($XDG_CONFIG_HOME??($HOME."/.config"))."/vim/.vimrc"|execute"source"$MYVIMRC'
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 if [[ -v commands[zoxide] ]] {
199     eval "$(zoxide init zsh)"
200     alias cd=z
201 }
202 ## git
203 alias ga='git add'
204 alias gdh='git diff HEAD'
205
206 ### hooks
207 autoload -Uz add-zsh-hook
208 _sev_exectime=
209 function sev_preexec {
210     # change terminal title to show command
211     print -n "\e]2;$(print -P '%#')${SSH_CLIENT+$USER@$HOST:}$1\e\\"
212     # save last exec time for bell
213     # XXX: does not run for blank cmdline
214     _sev_exectime=$SECONDS
215     # update gpg forward, to always have unique filename and avoid clashes
216     if [[ -v _GNUPG_SOCK_DEST_EXT ]] {
217         export _GNUPG_SOCK_DEST_EXT=$(date +%s).$RANDOM
218         export _GNUPG_SOCK_DEST=$_GNUPG_SOCK_DEST_BASE.$_GNUPG_SOCK_DEST_EXT
219     }
220 }
221 add-zsh-hook preexec sev_preexec
222 function sev_precmd {
223     # change terminal title
224     # TODO: update and send BEL when job status changes
225     print -Pn "\e]2;%(1j,%j,)%#${SSH_CLIENT+$USER@$HOST:}%~\e\\"
226     # bell if exec takes 5s
227     if (( SECONDS - _sev_exectime >= 5 )) print "\a"
228     # we could update vcs_info here, but let prompt take care of it
229     # if it doesn't use vcs, it can be ignored safely
230 }
231 add-zsh-hook precmd sev_precmd
232 function sev_chpwd {
233     # echo dir on cwd change
234     ls -AF
235 }
236 add-zsh-hook chpwd sev_chpwd
237
238 ### system-specific configs and aliases
239 case $OSTYPE; in
240     freebsd*)
241         # colors
242         export CLICOLOR=
243         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'
244
245         ## sound
246         function s { sysctl hw.snd.default_unit${1:+\=$1} }
247         alias vol mixer
248
249         ## install port dependencies from pkg (like pkgsrc `bmake bin-install')
250         # XXX: should probably use package-depends where possible, breaks when
251         #     port name is different to package name
252         #     (eg. graphics/sdl20 == sdl2, devel/glib20 == glib2, etc)
253         function portpkg {
254             case "$1" {
255             build|run)
256                 sudo pkg install -AU $(make ${1}-depends-list |
257                            sed 's_/usr/ports/_ _' | tr -d '\n')
258                 ;;
259             *)  echo "Usage: \`portpkg <build|run>' in a port directory"
260                 return 1;;
261             }
262         };;
263     netbsd)
264         ## sound
265         function s {
266             if [[ -z "$1" ]] {
267                 ll /dev/mixer /dev/sound /dev/audio
268                 return
269             }
270             for x in mixer sound audio; do
271                 ln -sf /dev/$x"$1" /dev/$x
272             done
273         }
274         function vol {
275             if [[ -z "$1" ]] {
276                 for x in $(mixerctl -a | grep 'outputs\.master'); do
277                     echo $x
278                 done
279                 return
280             }
281             mixerctl -w outputs.master"$2"="$1"
282         };;
283     *)
284         ## sound
285         # TODO: test alsa/oss/sndio/portaudio/pulse/pipewire in order of importance
286         function s {}
287         function vol {}
288 esac
289
290 ### modules & styles
291 ## vcs
292 zstyle ':vcs_info:*' enable git
293 #zstyle ':vcs_info:git*' check-for-changes true #too slow
294 zstyle ':vcs_info:git*:dotfiles' check-for-changes true
295 zstyle ':vcs_info:git*' check-for-staged-changes true
296 autoload -Uz vcs_info
297
298 ## compinit
299 zstyle ':completion:*' auto-description '[arg] %d'
300 zstyle ':completion:*' expand suffix
301 zstyle ':completion:*' format '# %d'
302 zstyle ':completion:*' group-name ''
303 zstyle ':completion:*' ignore-parents parent
304 zstyle ':completion:*' insert-unambiguous false
305 zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
306 zstyle ':completion:*' list-prompt '%B%i%b'
307 zstyle ':completion:*' list-suffixes true
308 zstyle ':completion:*' matcher-list '' 'm:{[:lower:]}={[:upper:]}' 'm:{[:lower:][:upper:]}={[:upper:][:lower:]} r:|[._-]=* r:|=*' 'm:{[:lower:][:upper:]}={[:upper:][:lower:]} l:|=* r:|=*'
309 zstyle ':completion:*' menu select=1
310 zstyle ':completion:*' original false
311 zstyle ':completion:*' select-prompt '%B%l%b'
312 zstyle ':completion:*' verbose true
313 autoload -Uz compinit
314 cache=${XDG_CACHE_HOME:-~/.cache}/zsh
315 [[ -d $cache ]] || mkdir -p $cache
316 compinit -d $cache/.zcompdump
317 unset cache
318
319 ### prompt
320 autoload -Uz promptinit && promptinit
321 prompt arrows
322
323 ### load site-specific
324 load-site-dotfile zshrc
This page took 0.044337 seconds and 2 git commands to generate.