Files
dotfiles/zshenv

315 lines
8.6 KiB
Bash

#
# ZSH Environment Setup
#
# Enable ZSH profiling?
if [[ -n "$ZPROF" ]]; then
zmodload zsh/zprof
fi
# Ensure compinit is NOT loaded before Zinit loads in ~/zshrc.
skip_global_compinit=1
# ==============================================================================
# PATH Setup
# ==============================================================================
# Ensure values in path variable are unique
typeset -U path
# Prevent loading ZSH startup from files /etc on macOS. The /etc/zprofile file
# screws around with PATH, so we want to avoid it, and instead manually load the
# files we care about.
if [[ "$OSTYPE" == "darwin"* ]]; then
# Disable loading startup files from /etc
unsetopt GLOBAL_RCS
# Setup default PATH just like /etc/zprofile does
if [ -x "/usr/libexec/path_helper" ]; then
eval $(/usr/libexec/path_helper -s)
fi
# Load /etc/zshenv if it exists
if [ -f "/etc/zshenv" ]; then
source "/etc/zshenv"
fi
fi
# ==============================================================================
# PATH Helpers
# ==============================================================================
path_list () {
print -l "${(@)path}"
}
path_remove () {
path=("${(@)path:#$1}")
}
path_append () {
if [ -d "$1" ]; then
path+="$1"
fi
}
path_prepend () {
if [ -d "$1" ]; then
path=("$1" "${(@)path:#$1}")
fi
}
# ==============================================================================
# Helpers
# ==============================================================================
command-exists() {
(( ${+commands[$1]} ))
return $?
}
command-path() {
if ! command-exists "$1"; then
return 1
fi
echo "${commands[$1]}"
}
source-if-exists() {
if [ -f "$1" ]; then
source "$1"
fi
}
# cached-eval executes a command with arguments and caches the output. On
# subsequent calls, if the source file has not changed, the output is sourced
# from the cache instead of re-executing the command. This optimizes performance
# for commands that are costly to execute but result in the same output unless
# their source files change.
#
# Arguments:
#
# $1 - source_file: The path to the source file that the command depends on.
# If this file is newer than the cache, the command is
# re-executed and the cache is updated.
# $@ - script: The command to execute and cache the output of.
#
# Example usage:
#
# cached-eval "$(command -v direnv)" direnv hook zsh
# cached-eval "$(command -v mise)" mise activate zsh
#
# The above commands will cache the output of `direnv hook zsh` and `mise
# activate zsh` respectively. If the source file is newer than the cache, the
# command is re-executed and cache is updated.
cached-eval() {
local source_file="$1"
shift 1
local script="$@"
local cache_dir="${ZSH_CACHED_EVAL_DIR:-$HOME/.local/share/zsh/cached-eval}"
if [[ ! -f "$source_file" ]]; then
echo "cached-eval: Source file not found: $source_file" >&2
return 1
fi
local md5_cmd="$(command-path md5 || command-path md5sum)"
local cache_hash="$(echo -n "${source_file}:${script}" | "$md5_cmd" | awk '{print $1}')"
local cache_file="${cache_dir}/${cache_hash}.cache.zsh"
if [ -z "$cache_hash" ]; then
echo "cached-eval: Failed to compute cache hash for: $script" >&2
return 1
fi
if [[ ! -f "$cache_file" || "$source_file" -nt "$cache_file" ]]; then
mkdir -p "$cache_dir"
echo "cached-eval: Updating cache for: $script --> $cache_file" >&2
echo -e "#\n# Generated by cached-eval: $script\n#\n" >| "$cache_file"
eval "$script" >>| "$cache_file"
fi
source "$cache_file"
}
# ==============================================================================
# System Environment Setup
# ==============================================================================
DOTFILES="$HOME/.dotfiles"
DOTBIN="$DOTFILES/bin"
DOTZSH="$DOTFILES/zsh"
# Editors
export EDITOR="emacsclient-wrapper"
export GEM_EDITOR="mate"
# Locale Setup
export LC_ALL="en_US.UTF-8"
export LANG="en_US.UTF-8"
# Ensure TMPDIR is the same for local and remote ssh logins
if [[ "$TMPDIR" == "/var/folders/"* ]] || [[ "$TMPDIR" == "" ]]; then
export TMPDIR="/tmp/user-$USER"
mkdir -p "$TMPDIR"
fi
export DOTZSH_SITEFUNS="$DOTZSH/site-functions"
export ZSH_COMPLETIONS="$HOME/.local/share/zsh/completions"
export ZSH_CACHED_EVAL_DIR="$HOME/.local/share/zsh/cached-eval"
# Ensure basic systems paths are in desired order
path_prepend "/bin"
path_prepend "/sbin"
path_prepend "/usr/bin"
path_prepend "/usr/sbin"
path_prepend "/usr/local/bin"
path_prepend "/usr/local/sbin"
# Add dotfiles' bin directory to PATH
path_prepend "$DOTBIN"
# Add user's bin directory to PATH
path_prepend "$HOME/bin"
# ==============================================================================
# Private Dotfiles Environment
# ==============================================================================
DOTPFILES="$DOTFILES/private"
if [ -f "$DOTPFILES/zshenv" ]; then
source "$DOTPFILES/zshenv"
fi
# ==============================================================================
# Third-party Environment Setup
# ==============================================================================
# Homebrew on Apple Silicon
if [ -f "/opt/homebrew/bin/brew" ]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
fi
if command-exists brew; then
typeset -A _brew_prefix_cache
brew-prefix() {
local package="${1:-__none__}"
if [[ -z "${_brew_prefix_cache[$package]}" ]]; then
_brew_prefix_cache[$package]="$(brew --prefix "$1" || return $?)"
fi
echo "${_brew_prefix_cache[$package]}"
}
export BREW_SITEFUNS="$(brew-prefix)/share/zsh/site-functions"
fi
# Linuxbrew
if [ -f "/home/linuxbrew/.linuxbrew/bin/brew" ]; then
# Inline linux-brew setup to improve shell startup speed by around 200ms.
export HOMEBREW_PREFIX="/home/linuxbrew/.linuxbrew"
export HOMEBREW_CELLAR="${HOMEBREW_PREFIX}/Cellar"
export HOMEBREW_REPOSITORY="${HOMEBREW_PREFIX}/Homebrew"
export MANPATH="${HOMEBREW_PREFIX}/share/man${MANPATH+:$MANPATH}"
export INFOPATH="${HOMEBREW_PREFIX}/share/info${INFOPATH+:$INFOPATH}"
path_prepend "${HOMEBREW_PREFIX}/bin"
path_prepend "${HOMEBREW_PREFIX}/sbin"
fi
# Nix
if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then
source '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'
# export NIX_PATH="$HOME/.nix-defexpr"
fi
# Android SDK environment setup.
if [ -d "$HOME/Library/Android/sdk" ]; then
export ANDROID_HOME="$HOME/Library/Android/sdk"
path_append "$ANDROID_HOME/emulator"
path_append "$ANDROID_HOME/tools"
path_append "$ANDROID_HOME/tools/bin"
path_append "$ANDROID_HOME/platform-tools"
fi
# Flutter environment setup
path_append "/opt/flutter/bin"
path_append "/opt/flutter/bin/cache/dart-sdk/bin"
# Use gnu-getop if available
path_prepend "/usr/local/opt/gnu-getopt/bin"
# Homebrew setup
export HOMEBREW_NO_ANALYTICS=1
# Kubernetes setup
export KUBECONFIG="$HOME/.kube/config"
if [ -d "$HOME/.krew" ]; then
export KREW_ROOT="$HOME/.krew"
path_append "$HOME/.krew/bin"
fi
# Use custom emacs install if available
path_prepend "/opt/emacs/bin"
# evm setup.
export EVM_MODE=user
export EVM_NATIVE_FULL_AOT=1
path_prepend "$HOME/.evm/shims"
# Set Emacs-related environment variables
export EMACS="emacs"
export EMACSCLIENT="emacsclient"
export LSP_USE_PLISTS="true" # Improve lsp-mode performance.
# On macOS we want to use the Emacs.app application bundle
if [[ "$OSTYPE" == "darwin"* ]]; then
path_prepend "/Applications/Emacs.app/Contents/MacOS/bin"
if [ ! -f "/Applications/Emacs.app/Contents/MacOS/bin/emacs" ] && \
[ -f "/Applications/Emacs.app/Contents/MacOS/Emacs" ]; then
export EMACS="/Applications/Emacs.app/Contents/MacOS/Emacs"
fi
fi
# Use custom tmux install if available
path_prepend "/opt/tmux/bin"
# Rust setup
export RUSTUP_HOME="$HOME/.rustup"
export CARGO_HOME="$HOME/.cargo"
path_prepend "$CARGO_HOME/bin"
export RUST_BACKTRACE=1
if command-exists sccache; then
export RUSTC_WRAPPER=sccache
else
export RUSTC_WRAPPER=""
fi
# pipx setup
path_prepend "$HOME/.local/bin"
# mise setup
export MISE_LIST_ALL_VERSIONS=1
path_prepend "$HOME/.local/share/mise/bin"
path_prepend "$HOME/.local/share/mise/shims"
# orbstack setup
source-if-exists "$HOME/.orbstack/shell/init.zsh"
path_prepend "$HOME/.orbstack/bin"
# Google Cloud SDK setup
source-if-exists "${HOMEBREW_PREFIX}/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.zsh.inc"
# ==============================================================================
# Local Overrides
# ==============================================================================
if [ -f "$HOME/.zshenv.local" ]; then
source "$HOME/.zshenv.local"
fi