config/profile (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
# shellcheck shell=bash
# profiling helpers
__profile_enabled=false
__timestamp() {
# date +%s
perl -MTime::HiRes=time -e 'printf "%d\n", time * 1000'
}
if [ $__profile_enabled = true ]; then
__previous_timestamp=$(__timestamp)
fi
_profile() {
if [ $__profile_enabled = true ]; then
_new_timestamp=$(__timestamp)
_diff=$((_new_timestamp - __previous_timestamp))
echo "$_diff $1"
__previous_timestamp=$_new_timestamp
fi
}
_profile entry
# The INTERACTIVE layer.
#
# Plain environment (PATH, XDG, locale, tool homes) lives in config/env, which
# is POSIX sh and is loaded by *every* shell — see its header. This file holds
# only what must NOT run in every shell: aliases, history, terminal setup, and
# anything expensive (theme, jenv, and whatever profile.d brings in).
#
# Reached via ~/.zshrc (interactive zsh) and ~/.profile (login bash). Sourcing
# config/env here too, because a login bash reaches ~/.profile without ever
# passing through ~/.zshenv. It is idempotent, so the double load is harmless.
if [ -r "$HOME/.env" ]; then
# shellcheck source=/dev/null
. "$HOME/.env"
else
# No ~/.env yet. A pull that does not run link.sh (by hand, or a sync without
# --link) can leave this file updated and the ~/.env symlink still absent
# - which would silently cost it PATH, XDG, locale and EDITOR. Fall back to
# the copy next to this file, found through the ~/.profile symlink that got
# us here. Harmless once link.sh has run.
__dotfiles_self=$(readlink "$HOME/.profile" 2>/dev/null)
if [ -n "$__dotfiles_self" ] && [ -r "${__dotfiles_self%/*}/env" ]; then
# shellcheck source=/dev/null
. "${__dotfiles_self%/*}/env"
fi
unset __dotfiles_self
fi
_profile env
# Everything below this point is bash/zsh syntax, and this file is not read
# only by bash and zsh: Ubuntu's /bin/sh is dash, and `sh -l` sources
# ~/.profile. dash cannot parse `[[ ]]` (noisy but survivable) and refuses a
# function named `exit`, which is a POSIX special builtin - that one is a fatal
# parse error, so dash dies here and never runs the command it was given. That
# silently broke every `sh -lc '...'` on every Linux host; it surfaced as a
# background daemon spawned that way failing before it could even create the
# log file its error message pointed at. macOS is unaffected: its /bin/sh is
# bash, so BASH_VERSION is set and the rest of the file still runs there.
#
# config/env above is POSIX and has already been sourced, so a plain sh keeps
# PATH, XDG, locale and EDITOR. It just stops before the interactive layer,
# which it had no use for anyway.
if [ -z "${BASH_VERSION-}" ] && [ -z "${ZSH_VERSION-}" ]; then
return 0 2>/dev/null || exit 0
fi
# Marks that this file is already running, so ~/.bashrc (which we may source at
# the very end, for login bash) doesn't source us straight back. See the header
# of config/bashrc for the full two-way handshake.
__dotfiles_profile=1
if [[ "$(uname)" == "Darwin" ]]
then
# Sometimes, when invoked via Karabiner, the HOME variable
# will not be defined, even with a login shell
: "${HOME:="/Users/$(whoami)"}"
elif [[ "$(uname)" == "Linux" ]]
then
if command -v wl-copy >/dev/null && command -v wl-paste >/dev/null; then
alias pbcopy='wl-copy'
alias pbpaste='wl-paste'
else
alias pbcopy='xclip -selection clipboard'
alias pbpaste='xclip -selection clipboard -o'
fi
fi
_profile clipboard_tools
# ripgrep
# Remind to use rg instead of ag
# ag() {
# >&2 echo "ERROR: You decided to switch to 'rg' (ripgrep)"
# return 1
# # command ag "$@"
# }
# if [[ -r "$HOME/.config/ripgrep/config" ]]; then
# export RIPGREP_CONFIG_PATH="$HOME/.config/ripgrep/config"
# fi
# XDG_{CONFIG,CACHE,DATA}_HOME are set in config/env.
# Set history file location and size.
SHELL_NAME="$(basename "$SHELL")"
SHELL_CACHE="$XDG_CACHE_HOME/$SHELL_NAME"
mkdir -p "$SHELL_CACHE"
HISTFILE="$SHELL_CACHE/history"
HISTSIZE=1000000
# SAVEHIST is read by zsh itself, which shellcheck can't lint for.
# shellcheck disable=SC2034
SAVEHIST=1000000
# detach from tmux by default
# Guard at call time, not definition time.
# functions and sources them in non-interactive tool shells that inherit
# $TMUX, where a bare `exit` must really exit (not detach the terminal).
exit() {
if [[ -n "${TMUX:-}" ]] && [[ $- == *i* ]]; then
tmux detach
else
builtin exit "$@"
fi
}
exists() { command -v "$1" >/dev/null 2>&1; } # Check if command exists (is in path).
lspath() { echo "$PATH" | tr ':' '\n'; } # list PATH entries
pathadd() { [[ -d "$1" ]] && PATH="$1"$(echo ":$PATH:" | sed "s|:$1:|:|" | sed 's|:$||'); }
pathapp() { [[ -d "$1" ]] && PATH=$(echo ":$PATH:" | sed "s|:$1:|:|" | sed 's|^:||')"$1"; }
# GPG
GPG_TTY=$(tty)
export GPG_TTY
pbsign() { pbpaste | gpg --clearsign | pbcopy; }
pbverify() { pbpaste | gpg --verify; }
# Show processes listening on TCP sockets
listening() {
lsof -n -P -i4TCP -sTCP:LISTEN \
| awk '{ print $9,$1,$2 }' \
| awk -F '\:' '{ print $2 }' \
| grep -E -v '^$' \
| column -t \
| sort -n
}
# https://sites.google.com/site/jimmyxu101/testing/use-tcpdump-to-monitor-http-traffic
httpdump() {
sudo tcpdump -A -i "${2:-lo0}" -s 0 -q "tcp port $1 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)"
}
alias clc="fc -ln -1 | sed -e 's/\\\\n/\\n/g' -e 's/\\\\t/\\t/g' | pbcopy"
# bash
# DISABLE_AUTO_TITLE, the core PATH entries and the less/PAGER settings are all
# in config/env.
# use bash like vi !
# set -o vi
_profile bash
# when using sudo, use alias expansion (otherwise sudo ignores your aliases)
alias sudo='sudo '
# color
export CLICOLOR=1
THEME_COLORS="$(theme --colors)"
export THEME_COLORS
if [ "$(theme --mode)" = "light" ]; then
export LSCOLORS=GxFxCxDxBxegedabagaced
else
export LSCOLORS=GxFxBxDxCxegedabagacad
fi
if exists bat ; then
# best for light: Coldark-Cold, Github, Monokai Extended Light, OneHalfLight, gruvbox-light
# best for dark: 1337, Coldark-Dark, Monokai Extended, OneHalfDark, gruvbox-dark
# config file in $XDG_CONFIG_HOME/bat/config takes precedence to this env var
export BAT_THEME='ansi' # works well with both light and dark themes
export BAT_STYLE='plain'
export MANPAGER="sh -c 'col -bx | bat -l man -p'"
export FZF_COMPLETION_OPTS='--preview '\''bat --color=always --style=numbers --line-range=:500 {}'\'
fi
if exists lsd
then
alias ls='lsd'
fi
_profile color
# VISUAL/EDITOR and the node environment are set in config/env.
# # ruby
# _profile ruby-start
# export RBENV_ROOT="${RBENV_ROOT:-"$XDG_CACHE_HOME/rbenv"}" # Set rbenv location.
# activate-rbenv() {
# if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi
# }
# activate-rbenv
# if [ -d "$HOME/.rbenv/bin" ] ; then
# pathapp "$HOME/.rbenv/bin"
# eval "$(rbenv init -)"
# fi
# # add user installs bin to path
# if which ruby >/dev/null && which gem >/dev/null; then
# pathapp "$(ruby -rubygems -e 'puts Gem.user_dir')/bin"
# fi
# _profile ruby-done
# python
# export VIRTUAL_ENV_DISABLE_PROMPT=1 # Add the virtualenv prompt myself.
# LANG/LC_* are set in config/env — mosh needs a UTF-8 locale in shells that
# never reach this file.
# If you want to use pyenv
# if [ -x "$(command -v pyenv)" ] ; then
# export PYENV_ROOT="$XDG_DATA_HOME/pyenv"
# pathadd "$PYENV_ROOT/bin"
# eval "$(pyenv init --path)"
# fi
# Instead of virtualenvwrapper's:
# mkvirtualenv -p <path/to/python> <name>
# I prefer to use:
# virtualenv --python=<path/to/python> .venv
# If you want to use virtualenvwrapper, uncomment this:
# if [ -r "$HOME/.local/pipx/venvs" ] ; then
# export WORKON_HOME="$XDG_DATA_HOME/virtualenvs"
# export VIRTUALENVWRAPPER_PYTHON="$HOME/.local/pipx/venvs/virtualenvwrapper/bin/python3.9"
# source "$HOME/.local/bin/virtualenvwrapper.sh"
# fi
export PYENV_VIRTUALENV_DISABLE_PROMPT=1
# The Python user bin is on PATH via config/env.
_profile python
# go — GOPATH and the go bin dirs are in config/env.
godocserver() { godoc "-http=localhost:6060"; }
_profile go
# rust — CARGO_HOME/RUSTUP_HOME and the cargo bin dir are in config/env, which
# also replaces what rustup's own $CARGO_HOME/env does (it only prepends PATH).
# GNU Arm Embedded Toolchain, used to build joeycastillo/Sensor-Watch, is on
# PATH via config/env.
# java
if exists jenv > /dev/null && [[ -z "$JENV_LOADED" ]]; then
eval "$(jenv init - --no-rehash)";
# export JAVA_HOME="${JAVA_HOME:-"$(jenv javahome)"}"
# export IDEA_JDK=$JAVA_HOME
# to make sure JAVA_HOME is set, enable this plugin - just need to run once:
# jenv enable-plugin export
fi
_profile jenv-init
# A gradlew / gradle wrapper.
# https://github.com/gdubw/gng
# This would be nice but it breaks existing IntelliJ projects
# export GRADLE_USER_HOME="$XDG_CACHE_HOME/gradle" # Also contains gradle.properties (symlink from XDG_CONFIG_HOME).
if exists gw > /dev/null; then
alias gradle=gw
fi
_profile java
# ANDROID_HOME and the colima/testcontainers docker vars are in config/env.
# Interactive setup linked in from elsewhere, one file per concern, in name
# order. This repo ships none: it is where a machine's own layer plugs in, with
# whatever needs a secret or names a host -- a token wrapper, API keys.
# ~/.localprofile, below, is for hand-written per-host setup and still has the
# last word.
#
# A function only to scope nullglob: zsh aborts on a glob matching nothing, and
# bash would hand the loop the literal pattern. The files are sourced inside it,
# so their plain assignments, exports and functions are global, but `local` or
# `typeset` in them would not be -- and under zsh neither would a `setopt`,
# which local_options reverts when the function returns.
__dotfiles_source_dir() {
if [ -n "${ZSH_VERSION-}" ]; then
setopt local_options null_glob
else
# Not `$(shopt -p nullglob)`: that exits 1 when the option is off, and a
# caller that sources this under `set -e` would die here without a word.
local __dotfiles_nullglob=''
shopt -q nullglob || __dotfiles_nullglob='shopt -u nullglob'
shopt -s nullglob
fi
local __dotfiles_f
for __dotfiles_f in "$1"/*.sh; do
# shellcheck source=/dev/null
. "$__dotfiles_f"
done
if [ -z "${ZSH_VERSION-}" ] && [ -n "$__dotfiles_nullglob" ]; then
eval "$__dotfiles_nullglob"
fi
}
__dotfiles_source_dir "${XDG_CONFIG_HOME:-$HOME/.config}/shell/profile.d"
unset -f __dotfiles_source_dir
_profile profile.d
macbook_chassis_regulatory_model() {
ioreg -l \
| grep '"regulatory-model-number"' \
| sed -E 's/.*<([^>]+).*/\1/' \
| cut -c1-10 \
| xxd -r -p \
| tr -d '\000'
}
_profile misc
if [[ -r /proc/cpuinfo ]] && \
grep -qi 'raspberry pi' /proc/cpuinfo
then
system_temperature() {
paste \
<(cat /sys/class/thermal/thermal_zone*/type) \
<(cat /sys/class/thermal/thermal_zone*/temp | sed 's/\(.\)..$/.\1°C/' ) \
| column -s $'\t' -t
if [[ -f /sys/class/thermal/cooling_device0/cur_state ]]
then
echo "Fan state: $(cat /sys/class/thermal/cooling_device0/cur_state)"
else
echo "No fan"
fi
}
fi
_profile raspberry_pi
# The kimi / cursor-agent / claude env vars are all in config/env.
if [ -n "$ZSH_VERSION" ]; then
[[ -d /opt/homebrew/share/zsh/site-functions/ ]] && fpath+=(/opt/homebrew/share/zsh/site-functions/)
fi
_profile zsh_specific
# Disable XON/XOFF flow control so Ctrl-Q/Ctrl-S work in apps like nvim
stty -ixon 2>/dev/null
# The Ghostty bin dir is on PATH via config/env.
_profile misc
# Interactive host-local setup. Plain host-local *environment* goes in
# ~/.localenv, which config/env sources for every shell.
# shellcheck source=/dev/null
[ -r "$HOME/.localprofile" ] && source "$HOME/.localprofile"
_profile local
# A *login* bash reads this file but never ~/.bashrc, so login and non-login
# interactive bash would otherwise diverge. Source it here to converge them.
# Skipped when ~/.bashrc is what sourced us, and for zsh, which has no such gap
# (a login interactive zsh reads both ~/.zprofile and ~/.zshrc).
if [ -n "${BASH_VERSION:-}" ] && [ -z "${__dotfiles_bashrc:-}" ] && [ -r "$HOME/.bashrc" ]; then
# shellcheck source=/dev/null
. "$HOME/.bashrc"
fi
_profile bashrc
_profile exit
# ~/bin is prepended to PATH in config/env.
# vim: foldmethod=marker filetype=sh tw=100
|