]> git.sev.monster Git - dotfiles.git/blob - etc/zsh/.zshenv
add librewolf
[dotfiles.git] / etc / zsh / .zshenv
1 ### functions
2 ## cleanup
3 # XXX: only call after relevant vars have been set up, defined early so that
4 #      below code can utilize it after they do so
5 function _sev_zcleanup {
6     local x p y
7
8     # gpg forwarding
9     if [[ -d $_sev_gpg_forward_dir && ( -z $1 || $1 == 'gpg-forward' ) ]] {
10         # clean up forward dirs if its session is dead or we ask for it
11         find $_sev_gpg_forward_dir -mindepth 1 -maxdepth 1 -type d |
12           while {read -r x} {
13             # NOTE: the only way we can get here is if we have not been
14             #       forwarded before, if the user asks for it, or during
15             #       logout. if our own pid already has a dir, it is most likely
16             #       stale, the user wants it removed, or something is very
17             #       broken—in all 3 of these cases the best choice is remove it.
18             p=$(basename $x)
19             if {[[ -v _sev_gpg_forward_clean || $$ == $p ]] ||
20                     ! kill -0 $p 2>/dev/null} {
21                 find $x -mindepth 1 -maxdepth 1 | while {read -r y} {
22                     # XXX: real dirs will stop unlink, consider it a feature
23                     unlink $y
24                 }
25                 # don't force in case something important is still there
26                 rmdir $x
27             }
28         }
29         # reset GNUPGHOME if we removed our own dir
30         if [[ $GNUPGHOME =~ '/.ssh_forward/\d+/*$' && ! -d $GNUPGHOME ]]
31             GNUPGHOME=${GNUPGHOME%$MATCH}
32     }
33
34     # custom tmp
35     # NOTE: _sev_tmp is not unset so session dirs will not be recreated if
36     #       called during runtime; unset _sev_tmp and re-source to fix
37     # NOTE: XDG dirs that use our tmp are not unset here, they are in zlogout
38     #       after this function is called
39     if [[ -d $_sev_tmp && ( -z $1 || $1 == 'tmp' ) ]] {
40         # clean up tmp dirs if its session is dead or we ask for it
41         find $_sev_tmp -mindepth 1 -maxdepth 1 -name '.session.*' -type d |
42           while {read -r x} {
43             # NOTE: same rationale as above
44             p=${$(basename $x)#.session.}
45             if {[[ -v _sev_tmp_clean || $$ == $p ]] ||
46                     ! kill -0 $p 2>/dev/null} {
47                 rm -rf $x
48             }
49         }
50     }
51 }
52
53 function _sev_setpath {
54     # NOTE: we utilize the fact that unique arrays keep the first occurrence and
55     #       remove any further occurences to capture elements from the old PATH
56     #       that we did not anticipate and shift them to the front, since they are
57     #       probably important to the system
58     # NOTE: tied arrays path and fpath already exist
59     typeset -gU path fpath
60     # add as many generic paths as possible to keep the order we want
61     # NOTE: /usr/{local,pkg,games} are unix/bsdisms
62     # XXX: PREFIX not validated, non-posix but Termux uses it, maybe others
63     # XXX: XDG specifies ~/.local/bin as the only user-writable dir for
64     #      executables, but we specify more; technically this is against spec
65     local -a syspath=("$path[@]")
66     path=({{${_sev_home:-~},~}{/.local,},{$PREFIX,}{,/opt,/opt/*{/*,},/usr{,/local,/pkg}}}/{s,}bin(N)
67           {$PREFIX,}/usr/{X11R{7,6}/bin,games}
68           # emulate Arch Linux flatpak-bindir.sh for use on other systems
69           {${XDG_DATA_HOME:-~/.local/share},{$PREFIX,}/var/lib}/flatpak/exports/bin)
70     local -i i len=$#path
71     path=("$path[@]" "$syspath[@]")
72     # remove bad paths
73     for (( i = 1; i <= $#path; i++ )) {
74         if [[ ! -d $path[$i] ]] {
75             path[$i]=()
76             ((i <= len)) && ((len--))
77             ((i--))
78             continue
79         }
80     }
81     # shift valid system paths to the front if there are any left
82     ((len > 0 && len < $#path)) && path=("${(@)path[len + 1, -1]}" "${(@)path[1, len]}")
83     # include our zsh dir in fpath. unlike above, we always prefer our paths
84     fpath=({${ZDOTDIR:-~/.zsh},{${_sev_home:-~},~}/.zsh}/functions/**/*(/N) "$fpath[@]")
85     # remove bad paths
86     for (( i = 1; i <= $#fpath; i++ )) {
87         if [[ ! -d $fpath[$i] ]] {
88             fpath[$i]=()
89             ((i--))
90             continue
91         }
92     }
93     # FPATH is not exported by default
94     export FPATH
95     typeset +U path fpath
96 }
97
98 ### common exports
99 export CHARSET=${CHARSET:-UTF-8}
100 export LANG=${LANG:-en_US.UTF-8}
101
102 ## alternative home for pulling in bin & config, used for zsu
103 [[ -v _sev_home ]] || export _sev_home=$HOME
104
105 ## fix broken term
106 # NOTE: we do this here instead of .zshrc since we might echo stuff
107 if [[ -t 1 ]] { # only if stdout is tty
108     [[ ! -v TERM ]] && export TERM=xterm-256color >/dev/null 2>&1
109     if [[ $#terminfo -eq 0 ]] {
110         _oldterm=$TERM
111         export TERM=xterm >/dev/null 2>&1
112         [[ -o interactive ]] &&
113           print -P "%F{red}!!! Can't find terminfo for $_oldterm, using $TERM%f"
114         unset _oldterm
115     }
116 }
117
118 ## path
119 if [[ ! -v _sev_setup_path || -o login ]] {
120     _sev_setpath
121     # NOTE: do not set _sev_setup_path, it is set in zprofile
122 }
123
124 ### home dir setup & exports
125 # XXX: traditionally, zshenv should just contain exports, and not touch the
126 #      filesystem. however, some system profile scripts that are sourced in the
127 #      system zprofile may attempt to do things that rely on some of these
128 #      vars. for example, `flatpak-bindir.sh` in the Arch Linux flatpak package
129 #      references $XDG_DATA_HOME with no fallback. since we do special handling
130 #      for these vars before we export them, we're forced to do it all here
131 #      instead of zprofile.
132
133 ## xdg local dir
134 # NOTE: need this for tmp, so confirm it exists.
135 # XXX: perms are not specified for XDG dirs except runtime, but I think 760
136 #      makes the most sense. shouldn't break anything since no one else should
137 #      be poking around in our dir.
138 [[ -e ~/.local ]] || mkdir -m760 ~/.local
139
140 ## tmp
141 # NOTE: specs say that POSIX tmp and XDG runtime directories should exist
142 #       until the last session is logged out (POSIX can exist for longer).
143 #       since we can't reliably keep track of sessions in a cross-platform
144 #       manner, the current implementation should use a separate directory per
145 #       toplevel session (i.e. SHLVL=1). this should placate most applications,
146 #       though it is not expressly spec compliant. this may also cause problems
147 #       with disowned applications that still try to use the directories after
148 #       the toplevel shell has already logged out and the dirs removed, but the
149 #       chances of that are slim.
150 if [[ ! -v _sev_tmp ]] {
151     # create personal TMPDIR under system tmp
152     t=${TMPDIR:-${TEMPDIR:-${TEMP:-${TMP:-/tmp}}}}/.home-$LOGNAME
153     [[ -e $t ]] || mkdir -m700 $t 2>/dev/null
154     _sev_tmp=~/.local/tmp
155     if [[ ! -d $t ]] {
156         # fallback TMPDIR to bare local directory or existing softlink
157         [[ -o interactive ]] &&
158           print -P "%F{orange}*** Can't create tmp dir $t, using $_sev_tmp%f"
159         [[ -h $_sev_tmp && ! -d _sev_tmp ]] && unlink $_sev_tmp 2>/dev/null
160         [[ ! -e $_sev_tmp ]] && mkdir -m700 $_sev_tmp 2>/dev/null
161         if [[ ! -d $_sev_tmp ]] {
162             _sev_tmp=${$(mktemp 2>/dev/null):/tmp}
163             [[ -o interactive ]] &&
164               print -P "%F{red}!!! Can't create tmp dir, using $_sev_tmp%f"
165         }
166     } elif [[ -f $_sev_tmp || ( -d $_sev_tmp && ! -h $_sev_tmp ) ]] {
167         # file or non-softlink directory is on our local dir
168         [[ -o interactive ]] &&
169           print -P "%F{orange}*** $_sev_tmp exists, can't link to tmp dir $t, ignoring it%f"
170         _sev_tmp=$t
171     } else {
172         # link local dir to tmp dir
173         if [[ -h $_sev_tmp && $_sev_tmp:P != $t:P ]] {
174             [[ -o interactive ]] &&
175               print -P "%F{orange}*** $_sev_tmp links to ${_sev_tmp:P} and not ${t:P}, unlinking it%f"
176             # XXX: race condition for existing sessions still using this dir
177             unlink $_sev_tmp 2>/dev/null
178         }
179         ln -s $t $_sev_tmp 2>/dev/null
180     }
181     if [[ -v _sev_tmp ]] {
182         # ensure dir is clean
183         _sev_zcleanup tmp
184         # finally create our subdir for this session
185         t=$_sev_tmp/.session.$$
186         if ! mkdir -m700 $t 2>/dev/null; then
187             [[ -o interactive ]] &&
188               print -P "%F{red}!!! Can't create session tmp subdir $t, using $_sev_tmp%f"
189             t=$_sev_tmp
190         fi
191         export _sev_tmp TMPDIR=$t TEMPDIR=$t TEMP=$t TMP=$t
192     }
193     unset t
194 }
195
196 ## xdg
197 if [[ ! -v _sev_setup_xdg ]] {
198     ## merge with any existing dirs and remove duplicates using unique arrays
199     # NOTE: we are accepting whatever value might be set for CONFIG and DATA;
200     #       if it wasn't set, we just use default and leave it unset
201     # NOTE: include and then remove CONFIG_HOME and DATA_HOME to ensure they
202     #       are not present in the array if it was added before we got to it
203
204     # source user dirs before other vars; technically it is against spec to
205     # include any of the below dirs there, but you never know what crazy shit
206     # people will do. I rather handle them sanely with our own code than let
207     # them override after the fact.
208     [[ -e $XDG_CONFIG_HOME/user-dirs.dirs ]] &&
209       emulate sh -c "source $XDG_CONFIG_HOME/user-dirs.dirs"
210
211     typeset -UT XDG_DATA_DIRS xdg_data_dirs
212     if [[ -v XDG_DATA_HOME ]] {
213         export XDG_DATA_HOME
214     } elif [[ ! -e ~/.local/share ]] {
215         mkdir -m760 ~/.local/share
216     }
217     xdg_data_dirs=($XDG_DATA_HOME /{opt,usr/local,usr/pkg,usr}/share
218       ${XDG_DATA_DIRS:+${xdg_data_dirs%%/}})
219     export XDG_DATA_DIRS
220
221     typeset -UT XDG_CONFIG_DIRS xdg_config_dirs
222     if [[ -v XDG_CONFIG_HOME ]] {
223         export XDG_CONFIG_HOME
224     } elif [[ ! -e ~/.config ]] {
225         mkdir -m760 ~/.config
226     }
227     # I am of the belief .local should follow FHS /usr/local...
228     [[ -e ~/.local/etc ]] || ln -s ~/.config ~/.local/etc
229     xdg_config_dirs=($XDG_CONFIG_HOME
230       ${XDG_CONFIG_DIRS:+${xdg_config_dirs%%/}}
231       {/opt,/usr/local,/usr/pkg,}/etc/xdg)
232     export XDG_CONFIG_DIRS
233
234     if [[ -v XDG_STATE_HOME ]] {
235         export XDG_STATE_HOME
236     } elif [[ ! -e ~/.local/state ]] {
237         mkdir -m760 ~/.local/state
238     }
239
240     if [[ -v XDG_CACHE_HOME ]] {
241         export XDG_CACHE_HOME
242     } else {
243         if [[ -v _sev_tmp ]] {
244             export XDG_CACHE_HOME=$_sev_tmp/.xdg.cache
245             [[ -e $XDG_CACHE_HOME ]] || mkdir -m700 $XDG_CACHE_HOME
246         } elif [[ ! -e ~/.cache ]] {
247             mkdir -m700 ~/.cache
248         }
249     }
250
251     if [[ -v XDG_RUNTIME_DIR ]] {
252         # NOTE: this can be set by systemd or other pre-shell supervisor, and
253         #       if any services were started such as pipewire, we need to use
254         #       the existing runtime dir so that we can get any existing
255         #       program sockets or other data
256         export XDG_RUNTIME_DIR
257     } elif [[ -v TMPDIR ]] {
258         # make runtime dir in our session-specific tmpdir
259         export XDG_RUNTIME_DIR=$TMPDIR/.xdg.runtime
260         # same as in tmpdir creation, ensure dir doesn't exist
261         if [[ -h $XDG_RUNTIME_DIR ]] {
262             unlink $XDG_RUNTIME_DIR 2>/dev/null
263         } elif [[ -e $XDG_RUNTIME_DIR ]] {
264             rm -rf $XDG_RUNTIME_DIR 2>/dev/null
265         }
266         mkdir -m700 $XDG_RUNTIME_DIR 2>/dev/null
267     }
268
269     export _sev_setup_xdg=
270 }
271
272 ### app setup & exports
273 # NOTE: we set these up here since some scripts might need them
274 ## gpg home
275 if [[ ! -v GNUPGHOME ]] {
276     export GNUPGHOME=${XDG_CONFIG_HOME:-~/.config}/gnupg
277     # move existing gnupg dir to our new home
278     if [[ -d ~/.gnupg && ! -d $GNUPGHOME ]] {
279         mv ~/.gnupg $GNUPGHOME
280     }
281 }
282
283 ## perl local lib
284 [[ ! -v PERL_LOCAL_LIB_ROOT && -v commands[perl] &&
285    -d $XDG_DATA_HOME/perl5/lib/perl5 ]] &&
286   eval $(perl -I$XDG_DATA_HOME/perl5/lib/perl5 \
287               -Mlocal::lib=$XDG_DATA_HOME/perl5 2>/dev/null)
288
289 ### load zshenv site-specific
290 autoload -Uz load-site-dotfile
291 load-site-dotfile zshenv
292
293 ### source .zprofile early for non-login shells that should be
294 if [[ ! -v _sev_first_display && ( -v DISPLAY || -v WAYLAND_DISPLAY ) ]] {
295     # most graphical login/session managers will spawn the user's shell as a
296     # parent of all child processes for that session. however, if the parent shell
297     # isn't a login shell for some reason, our .zprofile won't be run, and the
298     # environment won't be configured for child processes.
299     #
300     # XXX: .zprofile will be sourced by every new child shell if zsh is not
301     #      used to start the graphical session and the _sev_first_display var
302     #      isn't exported; for example, this previously happened when using
303     #      sway without a display manager in front of it to run a login shell.
304     #
305     #      this issue is not mitigated by .zprofile only loading what has not
306     #      already been loaded if the env vars preventing the load are not set;
307     #      in that case, every shell will think it is a fresh login shell.
308
309     # update gpgagent to use graphical pinentry
310     # XXX: will steal display from any other logged in graphical sessions, but
311     #      I consider this to be an unlikely scenario
312     _sev_refresh_gpgagent=
313
314     export _sev_first_display=
315     [[ ! -o login ]] && source ${ZDOTDIR:-~}/.zprofile
316 } elif [[ ${+TERMUX_VERSION} -eq 0 && ! -o login && $SHLVL -eq 1 ]] {
317     # Termux first process isn't login shell, so source early
318     source ${ZDOTDIR:-~}/.zprofile
319 }
This page took 0.058616 seconds and 4 git commands to generate.