When moving the configuration files to $XDG_CONFIG_HOME I forgot to change the line in .bashrc that sources the tmux configuration so bash was still trying to source ~/.tmux.conf, which no longer exists. This commit fixes that. Additionally, the color setting code has been factored out of tmux.conf into tmux-colors.conf (which can be sourced from bash profile and tmux.conf). This way the rest of the code in tmux.conf doesn't have to be executed again when changing the background color.
440 lines
15 KiB
Bash
440 lines
15 KiB
Bash
# shellcheck shell=bash
|
|
|
|
# Return immediately if non-interactive (makes FTP clients happy)
|
|
[[ "$-" == *i* ]] || return
|
|
|
|
##############################################################################
|
|
# Customize environment
|
|
##############################################################################
|
|
|
|
export XDG_CACHE_HOME="$HOME/.cache"
|
|
export XDG_CONFIG_HOME="$HOME/.config"
|
|
export XDG_DATA_HOME="$HOME/.local/share"
|
|
|
|
export EDITOR="vim"
|
|
export INPUTRC="$XDG_CONFIG_HOME/readline/inputrc"
|
|
export LANG="en_US.UTF-8"
|
|
export LANGUAGE="en_US"
|
|
export LC_ALL="en_US.UTF-8"
|
|
export LC_CTYPE="en_US.UTF-8"
|
|
export LESS="-i -j.49 -M -R -z-2"
|
|
export LESSHISTFILE="$XDG_CACHE_HOME/less/history"
|
|
export LESSHISTSIZE=1000
|
|
export LOCAL_PREFIX="/usr/local"
|
|
command -v brew &>/dev/null && LOCAL_PREFIX="$(brew --prefix)"
|
|
MANPATH="$(unset MANPATH; manpath)"
|
|
export MANPATH
|
|
export PAGER=less
|
|
export PYTHONSTARTUP="$XDG_CONFIG_HOME/python/startup.py"
|
|
# shellcheck disable=SC2016 # This expression is to be interpreted by vim, not bash.
|
|
export VIMINIT='let $MYVIMRC="$XDG_CONFIG_HOME/vim/vimrc" | source $MYVIMRC'
|
|
|
|
##############################################################################
|
|
# Customize PATH (and MANPATH)
|
|
##############################################################################
|
|
|
|
# Prevent path_helper from messing with the PATH when starting tmux.
|
|
# See: https://superuser.com/a/583502
|
|
# shellcheck disable=SC2123 # PATH is being intentionally manipulated here.
|
|
# shellcheck disable=SC1091 # /etc/profile is provided by macOS.
|
|
[ "$(uname)" == "Darwin" ] && { PATH=""; source /etc/profile; }
|
|
|
|
_prepend_path() { # 1: dir to add, 2: path variable to manipulate
|
|
if [ -d "$1" ] && [ -n "$2" ]; then
|
|
local _path="${!2}" # get path variable value
|
|
case ":$_path:" in
|
|
*":$1:"*) :;; # dir already in path, noop (:)
|
|
*) _path="$1${_path:+:}$_path";; # prepend (adding : if not empty)
|
|
esac
|
|
printf -v "$2" "%s" "$_path" # write back to path variable
|
|
fi
|
|
}
|
|
|
|
# Add custom bin dirs to PATH if they exist and are not already in PATH.
|
|
while read -r dir; do _prepend_path "$dir" PATH; done <<EOL
|
|
$LOCAL_PREFIX/bin
|
|
$LOCAL_PREFIX/opt/man-db/libexec/bin
|
|
$LOCAL_PREFIX/opt/coreutils/libexec/gnubin
|
|
$LOCAL_PREFIX/opt/gnu-sed/libexec/gnubin
|
|
$HOME/.local/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.
|
|
while read -r dir; do _prepend_path "$dir" MANPATH; done <<EOL
|
|
$LOCAL_PREFIX/share/man
|
|
$LOCAL_PREFIX/opt/man-db/libexec/man
|
|
$LOCAL_PREFIX/opt/coreutils/libexec/gnuman
|
|
$LOCAL_PREFIX/opt/gnu-sed/libexec/gnuman
|
|
$HOME/.local/share/man
|
|
EOL
|
|
|
|
unset dir
|
|
|
|
##############################################################################
|
|
# Customize shell options & variables
|
|
##############################################################################
|
|
|
|
shopt -s cdspell checkwinsize globstar histappend nocaseglob
|
|
set -o noclobber # Prevent overwriting files with output redirection.
|
|
|
|
# Eternal bash history (from https://stackoverflow.com/a/19533853)
|
|
HISTCONTROL=erasedups
|
|
HISTFILESIZE=
|
|
HISTSIZE=
|
|
HISTTIMEFORMAT="[%F %T] "
|
|
HISTFILE="$XDG_CACHE_HOME/bash/history"
|
|
|
|
# shellcheck disable=SC2034 # these variable are meant for use in shell only
|
|
{
|
|
# Color definitions (from http://ethanschoonover.com/solarized)
|
|
# NAME RGB HEX SGR ANSI TERMCOL XTERM/HEX L*A*B RGB HSB
|
|
# ---- ------- --- ---- ------- ----------- ----------- ----------- -----------
|
|
Base03=8 Base03_RGB="002B36" # 1;30 8 brblack 234 #1c1c1c 15 -12 -12 0 43 54 193 100 21
|
|
Base02=0 Base02_RGB="073642" # 0;30 0 black 235 #262626 20 -12 -12 7 54 66 192 90 26
|
|
Base01=10 Base01_RGB="586E75" # 1;32 10 brgreen 240 #585858 45 -07 -07 88 110 117 194 25 46
|
|
Base00=11 Base00_RGB="657B83" # 1;33 11 bryellow 241 #626262 50 -07 -07 101 123 131 195 23 51
|
|
Base0=12 Base0_RGB="839496" # 1;34 12 brblue 244 #808080 60 -06 -03 131 148 150 186 13 59
|
|
Base1=14 Base1_RGB="93A1A1" # 1;36 14 brcyan 245 #8a8a8a 65 -05 -02 147 161 161 180 9 63
|
|
Base2=7 Base2_RGB="EEE8D5" # 0;37 7 white 254 #e4e4e4 92 -00 10 238 232 213 44 11 93
|
|
Base3=15 Base3_RGB="FDF6E3" # 1;37 15 brwhite 230 #ffffd7 97 00 10 253 246 227 44 10 99
|
|
Yellow=3 Yellow_RGB="B58900" # 0;33 3 yellow 136 #af8700 60 10 65 181 137 0 45 100 71
|
|
Orange=9 Orange_RGB="CB4B16" # 1;31 9 brred 166 #d75f00 50 50 55 203 75 22 18 89 80
|
|
Red=1 Red_RGB="DC322F" # 0;31 1 red 160 #d70000 50 65 45 220 50 47 1 79 86
|
|
Magenta=5 Magenta_RGB="D33682" # 0;35 5 magenta 125 #af005f 50 65 -05 211 54 130 331 74 83
|
|
Violet=13 Violet_RGB="6C71C4" # 1;35 13 brmagenta 61 #5f5faf 50 15 -45 108 113 196 237 45 77
|
|
Blue=4 Blue_RGB="268BD2" # 0;34 4 blue 33 #0087ff 55 -10 -45 38 139 210 205 82 82
|
|
Cyan=6 Cyan_RGB="2AA198" # 0;36 6 cyan 37 #00afaf 60 -35 -05 42 161 152 175 74 63
|
|
Green=2 Green_RGB="859900" # 0;32 2 green 64 #5f8700 60 -20 65 133 153 0 68 100 60
|
|
|
|
PS1_DEFAULT=$(tput setaf $Cyan) # user@host color for local sessions
|
|
PS1_SSH=$(tput setaf $Yellow) # user@host color in SSH session
|
|
PS1_ROOT=$(tput setaf $Orange) # user@host color if logged in as root
|
|
PS1_PWD=$(tput setaf $Blue) # PWD color
|
|
PS1_EXIT=$(tput setaf $Red) # color for last exit code if non-zero
|
|
PS1_GIT=$(tput setaf $Green) # color for git branch
|
|
PS1_VENV=$(tput setaf $Violet) # color for python virtual env
|
|
PS1_JOBS=$(tput setaf $Magenta) # color for background jobs
|
|
PS1_SEP=" > " # separator between prompt parts
|
|
PS1_SEP_COLOR="" # is set in __update_colors
|
|
PS1_RST=$(tput sgr0)
|
|
|
|
GIT_PS1_SHOWDIRTYSTATE=1
|
|
GIT_PS1_SHOWSTASHSTATE=1
|
|
GIT_PS1_SHOWUNTRACKEDFILES=1
|
|
GIT_PS1_SHOWUPSTREAM=verbose
|
|
}
|
|
|
|
PROMPT_COMMAND=__ps1_set
|
|
PS2="... "
|
|
|
|
__ps1_set() {
|
|
local exit=$?
|
|
local sep="$PS1_SEP_COLOR$PS1_SEP"
|
|
|
|
local host=$PS1_DEFAULT
|
|
[ -n "$SSH_CLIENT" ] && host=$PS1_SSH
|
|
[ $EUID -eq 0 ] && host=$PS1_ROOT
|
|
|
|
local prompt=">>>>>>>>>>"
|
|
[ $EUID -eq 0 ] && prompt="##########"
|
|
|
|
local ps=()
|
|
[ $exit -ne 0 ] && ps+=("$PS1_EXIT$exit")
|
|
ps+=("$host\u@\h")
|
|
ps+=("$PS1_PWD\w")
|
|
type __git_ps1 && __git_ps1 '' '' "$PS1_GIT%s" && [ -n "$PS1" ] && ps+=("$PS1")
|
|
[ -n "$VIRTUAL_ENV" ] && ps+=("$PS1_VENV${VIRTUAL_ENV##*/}")
|
|
local j="\j" && [ "${j@P}" -gt 0 ] && ps+=("$PS1_JOBS${j@P} bg")
|
|
|
|
printf -v PS1 "$sep%s" "${ps[@]:1}"
|
|
PS1="\n${ps[0]}$PS1$PS1_RST\n${prompt:0:$SHLVL} "
|
|
} &>/dev/null
|
|
|
|
##############################################################################
|
|
# Customize shell aliases
|
|
##############################################################################
|
|
|
|
# Make `ls` group directories first if supported.
|
|
if ls --group-directories-first &>/dev/null; then
|
|
alias ls="ls -hF --group-directories-first --color=auto" # GNU
|
|
else
|
|
alias ls="ls -hF -G" # BSD
|
|
fi
|
|
|
|
# Force `ls` to use color output (e.g. for piping into `less`).
|
|
if ls --color=auto &>/dev/null; then
|
|
alias lsc="ls --color=always" # GNU
|
|
else
|
|
alias lsc="/usr/bin/env CLICOLOR_FORCE=1 ls" # BSD
|
|
fi
|
|
|
|
alias la="ls -a"
|
|
alias ll="ls -l"
|
|
alias llc="lsc -l"
|
|
alias lla="ls -la"
|
|
alias llac="lsc -la"
|
|
|
|
alias grep="grep --color=auto";
|
|
alias egrep="egrep --color=auto";
|
|
alias fgrep="fgrep --color=auto";
|
|
alias path='echo $PATH | tr -s ":" "\n"'
|
|
alias mpath='echo $MANPATH | tr -s ":" "\n"'
|
|
alias timer='echo "Timer started. Stop with Ctrl-D." && date && time cat && date'
|
|
|
|
alias tmux='tmux -f "$XDG_CONFIG_HOME/tmux/tmux.conf"'
|
|
|
|
# Head and tail as much as fits on screen
|
|
alias head='head -n $((${LINES:-15}-5))'
|
|
alias tail='tail -n $((${LINES:-15}-5))'
|
|
|
|
# A few options to get public IP address on command line. The dig solution
|
|
# below using the OpenDNS resolver doesn't work when connected to
|
|
# ExpressVPN because all DNS requests are handled by the ExpressVPN DNS
|
|
# servers and the OpenDNS DNS resolver is blocked.
|
|
alias ipinfo="curl -s ipinfo.io"
|
|
alias myip="curl -s https://ifconfig.co"
|
|
#alias myip="curl -s https://ifconfig.me"
|
|
#alias myip="dig +short myip.opendns.com @resolver1.opendns.com"
|
|
|
|
alias light='_update_colors light'
|
|
alias dark='_update_colors dark'
|
|
|
|
##############################################################################
|
|
# Terminal color management
|
|
##############################################################################
|
|
|
|
# Useful terminal control sequences:
|
|
#
|
|
# Sequence Abbrev Description
|
|
# ----- ----- -----------------------------
|
|
# ESC P DCS Device Control String
|
|
# ESC [ CSI Control Sequence Introducer
|
|
# ESC \ ST String Terminator
|
|
# ESC ] OSC Operating System Control
|
|
#
|
|
#
|
|
# More info at:
|
|
# * https://www.xfree86.org/4.8.0/ctlseqs.html
|
|
# * https://vt100.net/
|
|
# * https://iterm2.com/utilities/imgcat
|
|
|
|
# In tmux, OSC sequences can be forwarded to the underlying terminal by:
|
|
# * Wrapping the sequence with `DCS tmux; <sequence> ST`
|
|
# * Replacing ESC in <sequence> with ESC ESC.
|
|
_osc_start() {
|
|
if [ -n "$TMUX" ]; then
|
|
printf "\ePtmux;\e\e]"
|
|
else
|
|
printf "\e]"
|
|
fi
|
|
}
|
|
|
|
# Either ST or BEL (\a) can be used to end an OSC sequence. However, tmux
|
|
# requires ST to end its wrapping DCS.
|
|
_osc_end() {
|
|
if [ -n "$TMUX" ]; then
|
|
printf "\a\e\\"
|
|
else
|
|
printf "\a"
|
|
fi
|
|
}
|
|
|
|
_update_colors() {
|
|
export BACKGROUND="$1"
|
|
|
|
if [ "$BACKGROUND" = "light" ]; then
|
|
_set_terminal_colors $Base01_RGB $Base3_RGB $Red_RGB # fg bg cursor
|
|
PS1_SEP_COLOR=$(tput setaf $Base1)
|
|
else
|
|
_set_terminal_colors $Base1_RGB $Base03_RGB $Red_RGB # fg bg cursor
|
|
PS1_SEP_COLOR=$(tput setaf $Base01)
|
|
fi
|
|
|
|
if [ -n "$TMUX" ] && [ -f "$XDG_CONFIG_HOME/tmux/tmux-colors.conf" ]; then
|
|
tmux set-environment -g BACKGROUND "$BACKGROUND"
|
|
tmux source-file "$XDG_CONFIG_HOME/tmux/tmux-colors.conf"
|
|
fi
|
|
|
|
local ls_colors="$HOME/.config/dircolors/solarized-$BACKGROUND"
|
|
if type dircolors &>/dev/null && [ -f "$ls_colors" ]; then
|
|
eval "$(dircolors "$ls_colors")"
|
|
fi
|
|
}
|
|
|
|
_set_terminal_colors() { # 1: foreground, 2: background, 3: cursor
|
|
if [ -n "$ITERM_SESSION_ID" ]; then # iTerm2
|
|
_set_iterm2_colors "$1" "$2" "$3"
|
|
else # assume xterm
|
|
_set_xterm_colors "$1" "$2" "$3"
|
|
fi
|
|
}
|
|
|
|
# Documentation for iTerm2 at
|
|
# https://iterm2.com/documentation-escape-codes.html
|
|
# under the heading "Change the color palette".
|
|
_set_iterm2_colors() { # 1: foreground, 2: background, 3: cursor
|
|
local fg="$1" bg="$2" cursor="$3"
|
|
local n rgb
|
|
while read -r n rgb; do
|
|
_osc_start
|
|
printf "P%s%s" "$n" "$rgb"
|
|
_osc_end
|
|
done <<EOL
|
|
0 $Base02_RGB
|
|
1 $Red_RGB
|
|
2 $Green_RGB
|
|
3 $Yellow_RGB
|
|
4 $Blue_RGB
|
|
5 $Magenta_RGB
|
|
6 $Cyan_RGB
|
|
7 $Base2_RGB
|
|
8 $Base03_RGB
|
|
9 $Orange_RGB
|
|
a $Base01_RGB
|
|
b $Base00_RGB
|
|
c $Base0_RGB
|
|
d $Violet_RGB
|
|
e $Base1_RGB
|
|
f $Base3_RGB
|
|
g $fg
|
|
h $bg
|
|
i $fg
|
|
j $Base01_RGB
|
|
k $Base2_RGB
|
|
l $cursor
|
|
m $cursor
|
|
EOL
|
|
}
|
|
|
|
# Documentation for xterm at https://www.xfree86.org/4.8.0/ctlseqs.html
|
|
# under the heading "Operating System Controls".
|
|
_set_xterm_colors() { # $1 foreground, $2 background, $3 cursor
|
|
local fg="$1" bg="$2" cursor="$3"
|
|
local c rgb Ps
|
|
while read -r c rgb; do
|
|
# Send sequence OSC Ps BEL
|
|
# where Ps -> 4;c;spec
|
|
# c -> index of the ANSI color to change [0..15]
|
|
# spec -> RGB value of color as rgb:RR/GG/BB
|
|
_osc_start
|
|
printf "4;%s;rgb:%s/%s/%s" "$c" "${rgb:0:2}" "${rgb:2:2}" "${rgb:4:2}"
|
|
_osc_end
|
|
done <<EOL
|
|
0 $Base02_RGB
|
|
1 $Red_RGB
|
|
2 $Green_RGB
|
|
3 $Yellow_RGB
|
|
4 $Blue_RGB
|
|
5 $Magenta_RGB
|
|
6 $Cyan_RGB
|
|
7 $Base2_RGB
|
|
8 $Base03_RGB
|
|
9 $Orange_RGB
|
|
10 $Base01_RGB
|
|
11 $Base00_RGB
|
|
12 $Base0_RGB
|
|
13 $Violet_RGB
|
|
14 $Base1_RGB
|
|
15 $Base3_RGB
|
|
EOL
|
|
while read -r Ps rgb; do
|
|
# Send sequence OSC Ps ; Pt BEL
|
|
# where Ps -> foreground (10), background (11), or cursor (12)
|
|
# Pt -> RGB value of color as rgb:RR/GG/BB
|
|
_osc_start
|
|
printf "%s;rgb:%s/%s/%s" "$Ps" "${rgb:0:2}" "${rgb:2:2}" "${rgb:4:2}"
|
|
_osc_end
|
|
done <<EOL
|
|
10 $fg
|
|
11 $bg
|
|
12 $cursor
|
|
EOL
|
|
}
|
|
|
|
##############################################################################
|
|
# Add shell functions
|
|
##############################################################################
|
|
|
|
tree() { command tree --dirsfirst -FI '.git|Spotlight-V100|.fseventsd' "$@"; }
|
|
|
|
ltree() { tree -C "$@" | less -R; }
|
|
|
|
# Combined mkdir and cd
|
|
mkcd() { mkdir -p -- "$1" && cd -P -- "$1" || return; }
|
|
|
|
# Colorized `man`
|
|
man() {
|
|
local rst standout bold underline
|
|
|
|
rst=$(tput sgr0)
|
|
if [ "$BACKGROUND" = "light" ]; then
|
|
standout=$(tput -S <<<"$(echo -e "setaf $Base3\nsetab $Cyan")")
|
|
bold=$(tput -S <<<"$(echo -e "setaf $Blue")")
|
|
underline=$(tput -S <<<"$(echo -e "setaf $Base02\nsmul")")
|
|
else
|
|
standout=$(tput -S <<<"$(echo -e "setaf $Base03\nsetab $Cyan")")
|
|
bold=$(tput -S <<<"$(echo -e "setaf $Yellow")")
|
|
underline=$(tput -S <<<"$(echo -e "setaf $Base3\nsmul")")
|
|
fi
|
|
|
|
LESS_TERMCAP_so=$standout \
|
|
LESS_TERMCAP_md=$bold \
|
|
LESS_TERMCAP_us=$underline \
|
|
LESS_TERMCAP_se=$rst \
|
|
LESS_TERMCAP_me=$rst \
|
|
LESS_TERMCAP_ue=$rst \
|
|
GROFF_NO_SGR=1 \
|
|
command man "$@"
|
|
}
|
|
|
|
solarized() {
|
|
local rst name name_rgb rgb fg bg
|
|
|
|
rst=$(tput sgr0)
|
|
for name in Red Orange Yellow Green Cyan Blue Violet Magenta Base{0{3..0},{0..3}}
|
|
do
|
|
name_rgb=${name}_RGB
|
|
i=
|
|
rgb=${!name_rgb}
|
|
fg=$(tput setaf "${!name}")
|
|
bg=$(tput setab "${!name}")
|
|
printf "$bg%6s$rst $fg#$rgb %2d $name$rst\n" '' "${!name}"
|
|
done
|
|
}
|
|
|
|
# Print all 256 colors
|
|
colortest() {
|
|
local i j rst
|
|
rst=$(tput sgr0)
|
|
for i in $(seq 0 15); do
|
|
for j in $(seq 0 15); do
|
|
local n=$(( 16 * i + j ))
|
|
printf "$(tput setab $n) %3d " $n
|
|
done
|
|
echo "$rst"
|
|
done
|
|
}
|
|
|
|
##############################################################################
|
|
# Run external customizations
|
|
##############################################################################
|
|
|
|
stty -ixon # disable ctrl-s and ctrl-q
|
|
_update_colors "${BACKGROUND:-dark}"
|
|
|
|
# Enable available completion helpers
|
|
# shellcheck disable=SC1090 # no need to shellcheck bash completion files
|
|
while read -r d; do [ -d "$d" ] && for f in "$d"/*; do [ -f "$f" ] && . "$f"; done; done <<EOL
|
|
$LOCAL_PREFIX/etc/bash_completion.d
|
|
$XDG_CONFIG_HOME/bash/completion.d
|
|
EOL
|
|
unset d f
|
|
|
|
# Source a local bashrc if available
|
|
if [ -f "$XDG_CONFIG_HOME/bash/profile.local" ]; then
|
|
# shellcheck disable=SC1090
|
|
source "$XDG_CONFIG_HOME/bash/profile.local"
|
|
fi
|
|
|