zsh: make sure entries in PATH and MANPATH are in a consistent order

This commit is contained in:
Fernando Schauenburg 2024-07-27 03:30:23 +02:00
parent b47b986ae8
commit 3c7d3778ce

View file

@ -1,4 +1,26 @@
# General environment settings. have() {
command -v "$1" >/dev/null 2>&1
}
# Prepend $2 to variable $1 using $3 as separator, but only if $2 is not already
# contained in $1. This is useful for prepending to PATH while avoiding
# duplicates.
prepend_unique() {
local var="$1" new="$2" sep="${3-:}" # Default separator is colon.
local old="${(P)var}"
case "${sep}${old}${sep}" in
*"${sep}${new}${sep}"*) # Skip duplicate.
;;
"${sep}${sep}") # Variable was empty, set without separator.
typeset -g $var="${new}"
;;
*) # Prepend with separator.
typeset -g $var="${new}${sep}${old}"
;;
esac
}
setup_environment() { setup_environment() {
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}" export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
@ -14,91 +36,72 @@ setup_environment() {
export LESS="-i -j.49 -M -R -z-2" export LESS="-i -j.49 -M -R -z-2"
export LESSHISTFILE="$XDG_DATA_HOME/less/history" export LESSHISTFILE="$XDG_DATA_HOME/less/history"
export LESSHISTSIZE=1000 export LESSHISTSIZE=1000
export LOCAL_PREFIX="/usr/local"
export PAGER=less export PAGER=less
export PYTHONSTARTUP="$XDG_CONFIG_HOME/python/startup.py" export PYTHONSTARTUP="$XDG_CONFIG_HOME/python/startup.py"
} }
have() { setup_path_and_manpath() {
command -v "$1" >/dev/null 2>&1 # Prevent path_helper from messing with the PATH when starting tmux.
} #
# Clearing PATH before path_helper executes (from /etc/profile) will prevent it
# Prevent path_helper from messing with the PATH when starting tmux. # from prepending the default PATH to our (previously) chosen PATH, and will
# # allow the rest of this file to set up PATH and MANPATH correctly.
# Clearing PATH before path_helper executes (from /etc/profile) will prevent it #
# from prepending the default PATH to our (previously) chosen PATH, and will # For details see: https://superuser.com/a/583502
# allow the rest of this file to set up PATH and MANPATH correctly. #
#
# For details see: https://superuser.com/a/583502
#
setup_macos_path_helper() {
[ "$(uname -s)" = "Darwin" ] && { PATH=""; source /etc/profile; } [ "$(uname -s)" = "Darwin" ] && { PATH=""; source /etc/profile; }
local prefix="/usr/local"
have brew && prefix="$(brew --prefix)"
local custom_paths=(
"$prefix/opt/curl/bin"
"$prefix/bin"
"$HOME/.local/bin"
"$HOME/.bin"
)
local bindir=""
for bindir in $custom_paths; do
[ -d "$bindir" ] && prepend_unique PATH "$bindir"
done
export PATH
# Now that PATH is set, we should pick up all relevant man page locations, as
# for all directories ending in `<pathname>/bin` found in PATH, `manpath` will
# print the first existing directory of:
# - `<pathname>/man`
# - `<pathname>/../share/man`
# - `<pathname>/../man`
have manpath && { MANPATH="$(unset MANPATH; manpath)"; export MANPATH; }
} }
# Prepend $2 to variable $1 using $3 as separator, but only if $2 is not already # Some packages are installed by Homebrew in non-standard locations, in order to
# contained in $1. This is useful for prepending to PATH while avoiding # prevent conflicts with their system versions.
# duplicates. setup_brew_keg_only_packages() {
prepend_unique() { have brew || return
local var="$1"
local new="$2"
local sep="${3-:}" # Default separator is colon.
local old="${(P)var}"
case "${sep}${old}${sep}" in local packages=(
*"${sep}${new}${sep}"*) # Skip duplicate. make
;; grep
"${sep}${sep}") # Variable was empty, set without separator. gnu-tar
typeset -g $var="${new}" gnu-sed
;; findutils
*) # Prepend with separator. coreutils
typeset -g $var="${new}${sep}${old}" )
;;
esac local prefix="$(brew --prefix)"
local pkg="" bindir="" mandir=""
for pkg in $packages; do
bindir="$prefix/opt/$pkg/libexec/gnubin"
[ -d "$bindir" ] && prepend_unique PATH "$bindir"
mandir="$prefix/opt/$pkg/libexec/gnuman"
[ -d "$mandir" ] && prepend_unique MANPATH "$mandir"
done
} }
# Add custom bin dirs to PATH if they exist and are not already in PATH.
setup_path() {
local dir=""
while read -r dir; do
[ -d "$dir" ] && prepend_unique PATH "${dir}"
done <<EOL
$LOCAL_PREFIX/bin
$LOCAL_PREFIX/opt/curl/bin
$LOCAL_PREFIX/opt/make/libexec/gnubin
$LOCAL_PREFIX/opt/findutils/libexec/gnubin
$LOCAL_PREFIX/opt/gnu-sed/libexec/gnubin
$LOCAL_PREFIX/opt/gnu-tar/libexec/gnubin
$LOCAL_PREFIX/opt/grep/libexec/gnubin
$LOCAL_PREFIX/opt/coreutils/libexec/gnubin
$HOME/.local/bin
$HOME/.bin
EOL
}
# Prepend custom man directories to MANPATH if they exist, so that we get
# correct man page entries when multiple versions of a command are
# available.
setup_manpath() {
local dir=""
# TODO: check if I really need the next line, `manpath` add ~600ms to startup
# have manpath && MANPATH="$(unset MANPATH; manpath)"
while read -r dir; do
[ -d "$dir" ] && prepend_unique MANPATH "${dir}"
done <<-EOL
$LOCAL_PREFIX/share/man
$LOCAL_PREFIX/opt/curl/share/man
$LOCAL_PREFIX/opt/make/libexec/gnuman
$LOCAL_PREFIX/opt/findutils/libexec/gnuman
$LOCAL_PREFIX/opt/gnu-sed/libexec/gnuman
$LOCAL_PREFIX/opt/gnu-tar/libexec/gnuman
$LOCAL_PREFIX/opt/grep/libexec/gnuman
$LOCAL_PREFIX/opt/coreutils/libexec/gnuman
$HOME/.local/share/man
EOL
}
# These checks have to be done after PATH manipulation above so we can find
# installed programs if they are in the added paths.
setup_tools() { setup_tools() {
have nvim && EDITOR="nvim" have nvim && EDITOR="nvim"
[ -z $EDITOR ] && have vim && EDITOR="vim" [ -z $EDITOR ] && have vim && EDITOR="vim"
@ -138,10 +141,9 @@ setup_local_profile() {
# zmodload zsh/zprof # zmodload zsh/zprof
setup_environment setup_environment
setup_macos_path_helper setup_path_and_manpath
setup_path && export PATH setup_brew_keg_only_packages
setup_manpath && export MANPATH setup_tools # NOTE: this must be done _after_ `setup_environment`.
setup_tools
setup_wsl_display setup_wsl_display
setup_local_profile setup_local_profile
# zprof # zprof