# Login shell configuration — sourced once per session by zsh. # Sets environment variables, XDG paths, tool config, and host-specific overrides. # Guard against double-sourcing (e.g. nested login shells) [[ -n $__ZPROFILE_SOURCED ]] && return __ZPROFILE_SOURCED=1 # ── PATH ────────────────────────────────────────────────────────────────────── typeset -U path # deduplicate PATH entries # shellcheck disable=SC2206 # zsh tied array; no word-splitting concerns # Order: nix-profile (Home-Manager-provisioned tools) wins over the system # package manager so the same HM flake delivers the same tool versions on # both host (Arch) and VM (Ubuntu). ~/.local/bin keeps room for ad-hoc # user scripts. path=("$HOME/.nix-profile/bin" "$HOME/.local/bin" $path) # ── XDG Base Directories ───────────────────────────────────────────────────── export XDG_CONFIG_HOME="$HOME/.config" export XDG_DATA_HOME="$HOME/.local/share" export XDG_STATE_HOME="$HOME/.local/state" export XDG_CACHE_HOME="$HOME/.cache" # Pull in /etc/profile + /etc/profile.d/*.sh. The Arch zsh package used # to ship /etc/zsh/zprofile doing exactly this, but we removed system # zsh in favour of nix's zsh, so we replicate it here. This is how # flatpak (XDG_DATA_DIRS for app launchers), nix-daemon, locale, etc. # inject themselves into login shells. Sourced AFTER our PATH setup so # `typeset -U path` keeps nix-profile/bin + ~/.local/bin at the front # even if /etc/profile.d snippets try to prepend duplicates. [[ -r /etc/profile ]] && emulate sh -c 'source /etc/profile' # ── Locale ──────────────────────────────────────────────────────────────────── export LANG=en_US.UTF-8 # ── Terminal ────────────────────────────────────────────────────────────────── case $TERM in *256color|*truecolor) export COLORTERM=24bit ;; esac export TERMINAL='ghostty' export BROWSER='linkhandler' export OPENER='xdg-open' # ── Editors ─────────────────────────────────────────────────────────────────── export EDITOR='nvim' export VISUAL='nvim' export DIFFPROG='nvim -d' export MANPAGER='nvim +Man!' export MANWIDTH=999 # ── less ────────────────────────────────────────────────────────────────────── export LESS="-F --RAW-CONTROL-CHARS" [[ -r /usr/bin/source-highlight-esc.sh ]] && export LESSOPEN="| /usr/bin/source-highlight-esc.sh %s" # ── GPG / SSH ───────────────────────────────────────────────────────────────── unset SSH_AGENT_PID # Forwarded ssh-agent sockets live at /tmp/ssh-XXX/agent.NNN — a path # that disappears the moment the originating ssh connection drops, # leaving any long-running zellij pane (and its children: claude, # nvim, etc.) pointing at a dead socket. Keep a stable # ~/.ssh/agent.sock symlink that we re-aim on every login, and export # the stable path so processes inherit a value that survives # reconnects. Reattaching a zellij session after `ssh` → signing / # git-fetch keep working without any per-pane re-export. if [[ -n "$SSH_CONNECTION" && -S "$SSH_AUTH_SOCK" ]]; then stable_sock="$HOME/.ssh/agent.sock" if [[ "$SSH_AUTH_SOCK" != "$stable_sock" ]]; then ln -sfn "$SSH_AUTH_SOCK" "$stable_sock" fi export SSH_AUTH_SOCK="$stable_sock" unset stable_sock else # Local login: route ssh auth through gpg-agent. SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)" export SSH_AUTH_SOCK fi # ── FZF ─────────────────────────────────────────────────────────────────────── export FZF_DEFAULT_COMMAND="fd --type file --follow --hidden --exclude .git --color=always" export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND" export FZF_DIRS_COMMAND="fd --type d --follow --hidden --exclude .git --color=always" export FZF_DEFAULT_OPTS="--ansi --layout=reverse --inline-info --cycle --color=dark --color=fg:-1,bg:-1,hl:#5fff87,fg+:-1,bg+:-1,hl+:#ffaf5f --color=info:#af87ff,prompt:#5fff87,pointer:#ff87d7,marker:#ff87d7,spinner:#ff87d7" export FZF_CTRL_T_OPTS="--preview 'bat --color=always --style=numbers --line-range=:500 {}' --select-1 --exit-0" export FZF_CTRL_R_OPTS="--preview 'echo {}' --preview-window down:3:hidden:wrap --bind '?:toggle-preview' --sort --exact" export FZF_ALT_C_OPTS="--preview 'tree -C {} | head -200'" # ── Git prompt ──────────────────────────────────────────────────────────────── export GIT_PS1_SHOWDIRTYSTATE=1 export GIT_PS1_SHOWSTASHSTATE=1 unset GIT_PS1_SHOWUNTRACKEDFILES export GIT_PS1_SHOWUPSTREAM="verbose" export GIT_PS1_SHOWCONFLICTSTATE="yes" export GIT_PS1_DESCRIBE_STYLE="branch" export GIT_PS1_SHOWCOLORHINTS=1 export GIT_PS1_HIDE_IF_PWD_IGNORED=1 # ── GCC ─────────────────────────────────────────────────────────────────────── export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' # ── Java ────────────────────────────────────────────────────────────────────── # System AA fonts, GTK L&F, XDG prefs dir, GTK2 for compatibility export _JAVA_OPTIONS="-Dawt.useSystemAAFontSettings=on -Dswing.aatext=true -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel -Djava.util.prefs.userRoot=$XDG_CONFIG_HOME/java -Djdk.gtk.version=2" # Fix for non-reparenting WMs (sway, dwm, etc.) export _JAVA_AWT_WM_NONREPARENTING=1 # ── Miscellaneous ───────────────────────────────────────────────────────────── export QT_QPA_PLATFORMTHEME=qt6ct export NO_AT_BRIDGE=1 # suppress GTK accessibility bus warnings export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/podman/podman.sock" export INPUTRC="$XDG_CONFIG_HOME/sh/inputrc" # ── Wayland ─────────────────────────────────────────────────────────────────── export XDG_CURRENT_DESKTOP=sway # Prefer Wayland for Qt; fall back to xcb for apps without qt{5,6}-wayland. export QT_QPA_PLATFORM="wayland;xcb" # SDL2 defaults to X11; force Wayland with X11 fallback. SDL3 ignores this. export SDL_VIDEODRIVER="wayland,x11" # ── XDG cleanup: keep $HOME tidy ───────────────────────────────────────────── # https://wiki.archlinux.org/title/XDG_Base_Directory#Partial export CARGO_HOME="$XDG_DATA_HOME/cargo" export CUDA_CACHE_PATH="$XDG_CACHE_HOME/nv" export GOPATH="$XDG_DATA_HOME/go" export GRADLE_USER_HOME="$XDG_DATA_HOME/gradle" export NODE_REPL_HISTORY="$XDG_DATA_HOME/node_repl_history" export PASSWORD_STORE_DIR="$XDG_DATA_HOME/password-store" export RUFF_CACHE_DIR="$XDG_CACHE_HOME/ruff" export RUSTUP_HOME="$XDG_DATA_HOME/rustup" export WGETRC="$XDG_CONFIG_HOME/wget/wgetrc" export WINEPREFIX="$XDG_DATA_HOME/wineprefixes/default" # ── Host-specific ───────────────────────────────────────────────────────────── case $(uname -n) in halley2) export LIBVA_DRIVER_NAME="iHD" export MESA_LOADER_DRIVER_OVERRIDE="iris" export VAAPI_MPEG4_ENABLED=true ;; hercules) export OCL_ICD_VENDORS=nvidia # shellcheck disable=SC1091 # optional, loaded only on hosts that have it [[ -r "$XDG_CONFIG_HOME/sh/work-envrc" ]] && source "$XDG_CONFIG_HOME/sh/work-envrc" ;; esac # ── Auto-start sway on VT1 ──────────────────────────────────────────────────── if [[ -z $WAYLAND_DISPLAY && $XDG_VTNR == 1 ]]; then export XDG_SESSION_TYPE=wayland exec sway fi