mirror of
https://github.com/robbyrussell/oh-my-zsh.git
synced 2026-09-30 06:56:06 +02:00
_omz_git_head reports through $REPLY, which stayed set for the rest of startup and could overwrite caller state or be mistaken for the result of an unrelated read. Call it inside an anonymous function that declares REPLY local. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
285 lines
8.9 KiB
Bash
285 lines
8.9 KiB
Bash
# ANSI formatting function (\033[<code>m)
|
|
# 0: reset, 1: bold, 4: underline, 22: no bold, 24: no underline, 31: red, 33: yellow
|
|
omz_f() {
|
|
[ $# -gt 0 ] || return
|
|
IFS=";" printf "\033[%sm" $*
|
|
}
|
|
# If stdout is not a terminal ignore all formatting
|
|
[ -t 1 ] || omz_f() { :; }
|
|
|
|
# Protect against non-zsh execution of Oh My Zsh (use POSIX syntax here)
|
|
[ -n "$ZSH_VERSION" ] || {
|
|
omz_ptree() {
|
|
# Get process tree of the current process
|
|
pid=$$; pids="$pid"
|
|
while [ ${pid-0} -ne 1 ] && ppid=$(ps -e -o pid,ppid | awk "\$1 == $pid { print \$2 }"); do
|
|
pids="$pids $pid"; pid=$ppid
|
|
done
|
|
|
|
# Show process tree
|
|
case "$(uname)" in
|
|
Linux) ps -o ppid,pid,command -f -p $pids 2>/dev/null ;;
|
|
Darwin|*) ps -o ppid,pid,command -p $pids 2>/dev/null ;;
|
|
esac
|
|
|
|
# If ps command failed, try Busybox ps
|
|
[ $? -eq 0 ] || ps -o ppid,pid,comm | awk "NR == 1 || index(\"$pids\", \$2) != 0"
|
|
}
|
|
|
|
{
|
|
shell=$(ps -o pid,comm | awk "\$1 == $$ { print \$2 }")
|
|
printf "$(omz_f 1 31)Error:$(omz_f 22) Oh My Zsh can't be loaded from: $(omz_f 1)${shell}$(omz_f 22). "
|
|
printf "You need to run $(omz_f 1)zsh$(omz_f 22) instead.$(omz_f 0)\n"
|
|
printf "$(omz_f 33)Here's the process tree:$(omz_f 22)\n\n"
|
|
omz_ptree
|
|
printf "$(omz_f 0)\n"
|
|
} >&2
|
|
|
|
return 1
|
|
}
|
|
|
|
# Check if in emulation mode, if so early return
|
|
# https://github.com/ohmyzsh/ohmyzsh/issues/11686
|
|
[[ "$(emulate)" = zsh ]] || {
|
|
printf "$(omz_f 1 31)Error:$(omz_f 22) Oh My Zsh can't be loaded in \`$(emulate)\` emulation mode.$(omz_f 0)\n" >&2
|
|
return 1
|
|
}
|
|
|
|
unset -f omz_f
|
|
|
|
# If ZSH is not defined, use the current script's directory.
|
|
[[ -n "$ZSH" ]] || export ZSH="${${(%):-%x}:a:h}"
|
|
|
|
# Set ZSH_CUSTOM to the path where your custom config files
|
|
# and plugins exists, or else we will use the default custom/
|
|
[[ -n "$ZSH_CUSTOM" ]] || ZSH_CUSTOM="$ZSH/custom"
|
|
|
|
# Set ZSH_CACHE_DIR to the path where cache files should be created
|
|
# or else we will use the default cache/
|
|
[[ -n "$ZSH_CACHE_DIR" ]] || ZSH_CACHE_DIR="$ZSH/cache"
|
|
|
|
# Make sure $ZSH_CACHE_DIR is writable, otherwise use a directory in $HOME
|
|
if [[ ! -w "$ZSH_CACHE_DIR" ]]; then
|
|
ZSH_CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/oh-my-zsh"
|
|
fi
|
|
|
|
# Create cache and completions dir and add to $fpath
|
|
mkdir -p "$ZSH_CACHE_DIR/completions"
|
|
(( ${fpath[(Ie)$ZSH_CACHE_DIR/completions]} )) || fpath=("$ZSH_CACHE_DIR/completions" $fpath)
|
|
|
|
# Check for updates on initial load...
|
|
source "$ZSH/tools/check_for_upgrade.sh"
|
|
|
|
# Initializes Oh My Zsh
|
|
|
|
# add a function path
|
|
fpath=($ZSH/{functions,completions} $ZSH_CUSTOM/{functions,completions} $fpath)
|
|
|
|
# Load all stock functions (from $fpath files) called below.
|
|
autoload -U compaudit compinit zrecompile
|
|
|
|
is_plugin() {
|
|
local base_dir=$1
|
|
local name=$2
|
|
builtin test -f $base_dir/plugins/$name/$name.plugin.zsh \
|
|
|| builtin test -f $base_dir/plugins/$name/_$name
|
|
}
|
|
|
|
# Add all defined plugins to fpath. This must be done
|
|
# before running compinit.
|
|
for plugin ($plugins); do
|
|
if is_plugin "$ZSH_CUSTOM" "$plugin"; then
|
|
fpath=("$ZSH_CUSTOM/plugins/$plugin" $fpath)
|
|
elif is_plugin "$ZSH" "$plugin"; then
|
|
fpath=("$ZSH/plugins/$plugin" $fpath)
|
|
else
|
|
echo "[oh-my-zsh] plugin '$plugin' not found"
|
|
fi
|
|
done
|
|
|
|
# Figure out the SHORT hostname
|
|
if [[ "$OSTYPE" = darwin* ]]; then
|
|
# macOS's $HOST changes with dhcp, etc. Use LocalHostName if possible.
|
|
SHORT_HOST=$(scutil --get LocalHostName 2>/dev/null) || SHORT_HOST="${HOST/.*/}"
|
|
else
|
|
SHORT_HOST="${HOST/.*/}"
|
|
fi
|
|
|
|
# Save the location of the current completion dump file.
|
|
if [[ -z "$ZSH_COMPDUMP" ]]; then
|
|
ZSH_COMPDUMP="${ZDOTDIR:-$HOME}/.zcompdump-${SHORT_HOST}-${ZSH_VERSION}"
|
|
fi
|
|
|
|
# Resolve the commit $ZSH is checked out at into $REPLY by reading the git
|
|
# directory, so that no git process is forked on every startup.
|
|
# Handles .git files (worktrees, submodules), worktree common dirs, detached
|
|
# HEADs and packed refs. Returns 1 if anything is unexpected.
|
|
_omz_git_head() {
|
|
local gitdir="$ZSH/.git" common head ref
|
|
local -a lines
|
|
REPLY=
|
|
|
|
# .git may be a file pointing at the real git dir
|
|
if [[ -f "$gitdir" ]]; then
|
|
read -r head 2>/dev/null < "$gitdir" || return 1
|
|
gitdir="${head#gitdir: }"
|
|
[[ "$gitdir" = /* ]] || gitdir="$ZSH/$gitdir"
|
|
fi
|
|
|
|
# worktrees keep their refs in the common git dir
|
|
common="$gitdir"
|
|
if [[ -f "$gitdir/commondir" ]]; then
|
|
read -r common 2>/dev/null < "$gitdir/commondir" || return 1
|
|
[[ "$common" = /* ]] || common="$gitdir/$common"
|
|
fi
|
|
|
|
[[ -r "$gitdir/HEAD" ]] || return 1
|
|
read -r head 2>/dev/null < "$gitdir/HEAD" || return 1
|
|
|
|
# detached HEAD: the file holds the commit itself
|
|
[[ "$head" = ref:\ * ]] || { REPLY="$head"; return 0 }
|
|
|
|
ref="${head#ref: }"
|
|
if [[ -r "$common/$ref" ]]; then
|
|
read -r REPLY 2>/dev/null < "$common/$ref" || return 1
|
|
[[ "$REPLY" != ref:\ * ]] || return 1
|
|
return 0
|
|
fi
|
|
|
|
[[ -r "$common/packed-refs" ]] || return 1
|
|
lines=("${(@f)$(<"$common/packed-refs")}")
|
|
REPLY="${lines[(r)* ${(b)ref}]%% *}"
|
|
[[ -n "$REPLY" ]]
|
|
}
|
|
|
|
# Construct zcompdump OMZ metadata. The helper reports through $REPLY, so
|
|
# call it in a scope that keeps that out of the global namespace.
|
|
() {
|
|
local REPLY
|
|
_omz_git_head || REPLY="$(builtin cd -q "$ZSH"; git rev-parse HEAD 2>/dev/null)"
|
|
typeset -g zcompdump_revision="#omz revision: $REPLY"
|
|
}
|
|
zcompdump_fpath="#omz fpath: $fpath"
|
|
unset -f _omz_git_head
|
|
|
|
# Delete the zcompdump file if OMZ zcompdump metadata changed
|
|
if ! command grep -q -Fx "$zcompdump_revision" "$ZSH_COMPDUMP" 2>/dev/null \
|
|
|| ! command grep -q -Fx "$zcompdump_fpath" "$ZSH_COMPDUMP" 2>/dev/null; then
|
|
command rm -f "$ZSH_COMPDUMP"
|
|
zcompdump_refresh=1
|
|
fi
|
|
|
|
if [[ "$ZSH_DISABLE_COMPFIX" != true ]]; then
|
|
source "$ZSH/lib/compfix.zsh"
|
|
# Load only from secure directories
|
|
# Reset the flag compinit sets when -i excludes insecure entries
|
|
unset _comp_secure
|
|
compinit -i -d "$ZSH_COMPDUMP"
|
|
# If completion insecurities exist, warn the user
|
|
[[ "$_comp_secure" == yes ]] && handle_completion_insecurities &|
|
|
else
|
|
# If the user wants it, load from all found directories
|
|
compinit -u -d "$ZSH_COMPDUMP"
|
|
fi
|
|
|
|
# Append zcompdump metadata if missing
|
|
if (( $zcompdump_refresh )) \
|
|
|| ! command grep -q -Fx "$zcompdump_revision" "$ZSH_COMPDUMP" 2>/dev/null; then
|
|
# Use `tee` in case the $ZSH_COMPDUMP filename is invalid, to silence the error
|
|
# See https://github.com/ohmyzsh/ohmyzsh/commit/dd1a7269#commitcomment-39003489
|
|
tee -a "$ZSH_COMPDUMP" &>/dev/null <<EOF
|
|
|
|
$zcompdump_revision
|
|
$zcompdump_fpath
|
|
EOF
|
|
fi
|
|
unset zcompdump_revision zcompdump_fpath zcompdump_refresh
|
|
|
|
# zcompile the completion dump file if the .zwc is older or missing.
|
|
if command mkdir "${ZSH_COMPDUMP}.lock" 2>/dev/null; then
|
|
zrecompile -q -p "$ZSH_COMPDUMP"
|
|
command rm -rf "$ZSH_COMPDUMP.zwc.old" "${ZSH_COMPDUMP}.lock"
|
|
fi
|
|
|
|
_omz_source() {
|
|
local context filepath="$1"
|
|
|
|
# Construct zstyle context based on path
|
|
case "$filepath" in
|
|
lib/*) context="lib:${filepath:t:r}" ;; # :t = lib_name.zsh, :r = lib_name
|
|
plugins/*) context="plugins:${filepath:h:t}" ;; # :h = plugins/plugin_name, :t = plugin_name
|
|
esac
|
|
|
|
local disable_aliases=0
|
|
zstyle -T ":omz:${context}" aliases || disable_aliases=1
|
|
|
|
# Back up alias names prior to sourcing
|
|
local -A aliases_pre galiases_pre
|
|
if (( disable_aliases )); then
|
|
aliases_pre=("${(@kv)aliases}")
|
|
galiases_pre=("${(@kv)galiases}")
|
|
fi
|
|
|
|
# Source file from $ZSH_CUSTOM if it exists, otherwise from $ZSH
|
|
if [[ -f "$ZSH_CUSTOM/$filepath" ]]; then
|
|
source "$ZSH_CUSTOM/$filepath"
|
|
elif [[ -f "$ZSH/$filepath" ]]; then
|
|
source "$ZSH/$filepath"
|
|
fi
|
|
|
|
# Unset all aliases that don't appear in the backed up list of aliases
|
|
if (( disable_aliases )); then
|
|
if (( #aliases_pre )); then
|
|
aliases=("${(@kv)aliases_pre}")
|
|
else
|
|
(( #aliases )) && unalias "${(@k)aliases}"
|
|
fi
|
|
if (( #galiases_pre )); then
|
|
galiases=("${(@kv)galiases_pre}")
|
|
else
|
|
(( #galiases )) && unalias "${(@k)galiases}"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Load all of the lib files in ~/.oh-my-zsh/lib that end in .zsh
|
|
# TIP: Add files you don't want in git to .gitignore
|
|
for lib_file ("$ZSH"/lib/*.zsh); do
|
|
_omz_source "lib/${lib_file:t}"
|
|
done
|
|
unset lib_file
|
|
|
|
# Load all of the plugins that were defined in ~/.zshrc
|
|
for plugin ($plugins); do
|
|
_omz_source "plugins/$plugin/$plugin.plugin.zsh"
|
|
done
|
|
unset plugin
|
|
|
|
# Load all of your custom configurations from custom/
|
|
for config_file ("$ZSH_CUSTOM"/*.zsh(N)); do
|
|
source "$config_file"
|
|
done
|
|
unset config_file
|
|
|
|
# Load the theme
|
|
is_theme() {
|
|
local base_dir=$1
|
|
local name=$2
|
|
builtin test -f $base_dir/$name.zsh-theme
|
|
}
|
|
|
|
if [[ -n "$ZSH_THEME" ]]; then
|
|
if is_theme "$ZSH_CUSTOM" "$ZSH_THEME"; then
|
|
source "$ZSH_CUSTOM/$ZSH_THEME.zsh-theme"
|
|
elif is_theme "$ZSH_CUSTOM/themes" "$ZSH_THEME"; then
|
|
source "$ZSH_CUSTOM/themes/$ZSH_THEME.zsh-theme"
|
|
elif is_theme "$ZSH/themes" "$ZSH_THEME"; then
|
|
source "$ZSH/themes/$ZSH_THEME.zsh-theme"
|
|
else
|
|
echo "[oh-my-zsh] theme '$ZSH_THEME' not found"
|
|
fi
|
|
fi
|
|
|
|
# set completion colors to be the same as `ls`, after theme has been loaded
|
|
[[ -z "$LS_COLORS" ]] || zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}"
|