dotfiles/roles/bash/files/profile
Fernando Schauenburg 655884c3f1 bash: fix OSC sequences
The function calls where somethimes too slow and the terminal timed out
before accepting the entire escape sequence. By constructing the whole
string before sending via printf this problem is avoided.

I originally noticed this issue when using Alacritty on WSL, where
apparently the communication via ConPTY can be a bit slow.
2020-12-16 18:21:51 +01:00

442 lines
16 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_DATA_HOME/less/history"
export LESSHISTSIZE=1000
export LOCAL_CONFIG="$HOME/.local/etc"
export LOCAL_PREFIX="/usr/local"
if command -v brew &>/dev/null; then
LOCAL_PREFIX="$(brew --prefix)"
export HOMEBREW_NO_ANALYTICS=1
export HOMEBREW_NO_AUTO_UPDATE=1
fi
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_DATA_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_EXIT=$(tput setaf $Red) # color for last exit code if non-zero
PS1_ROOT=$(tput setaf $Orange) # logged in as root
PS1_SSH=$(tput setaf $Yellow) # hostname for SSH sessions
PS1_PWD=$(tput setaf $Cyan) # PWD color
PS1_GIT=$(tput setaf $Blue) # 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 prompt=">>>>>>>>>>"
local ps=()
[ $exit -ne 0 ] && ps+=("$PS1_EXIT$exit")
[ $EUID -eq 0 ] && { ps+=("$PS1_ROOT\u"); prompt="##########"; }
[ -n "$SSH_CONNECTION" ] && ps+=("$PS1_SSH\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")
local extra=""
[ ${#ps[@]} -gt 1 ] && printf -v extra "$sep%s" "${ps[@]:1}"
PS1="\n${ps[0]}$extra$PS1_RST\n${prompt:0:$SHLVL} "
} &>/dev/null
##############################################################################
# Customize shell aliases
##############################################################################
# ls: make `ls` group directories first if supported.
# lsc: force `ls` to use color output (e.g. for piping into `less`).
if command -v exa >/dev/null; then
alias ls="exa -F --git --group-directories-first --group --links -I'.git'"
alias la="ls -a"
alias lt="ls -lT"
alias lta="ls -lTa"
alias lsc="ls --color=always"
elif ls --group-directories-first --color=auto &>/dev/null 2>&1; then
# GNU ls
alias ls="ls -hF --group-directories-first --color=auto"
alias la="ls -A"
alias lsc="ls --color=always"
else
# BSD ls (e.g. macOS)
alias ls="ls -hF -G"
alias la="ls -A"
alias lsc="/usr/bin/env CLICOLOR_FORCE=1 ls"
fi
alias ll="ls -l"
alias lla="la -l"
alias g='git'
alias ga='git a'
alias gc='git commit'
alias gd='git d'
alias gcm='git cm'
alias gl='git l'
alias gla='git la'
alias gln='git ln'
alias gs='git s'
alias gss='git ss'
alias v='vim'
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.
# Either ST or BEL (\a) can be used to end an OSC sequence. However, tmux
# requires ST to end its wrapping DCS.
if [ -n "$TMUX" ]; then
_OSC=$(printf "\ePtmux;\e\e]")
_ST=$(printf "\a\e\\")
else
_OSC=$(printf "\e]")
_ST=$(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 key rgb
while read -r key rgb; do
printf "%s1337;SetColors=%s=%s%s" "$_OSC" "$key" "${rgb}" "$_ST"
done <<EOL
black $Base02_RGB
red $Red_RGB
green $Green_RGB
yellow $Yellow_RGB
blue $Blue_RGB
magenta $Magenta_RGB
cyan $Cyan_RGB
white $Base2_RGB
br_black $Base03_RGB
br_red $Orange_RGB
br_green $Base01_RGB
br_yellow $Base00_RGB
br_blue $Base0_RGB
br_magenta $Violet_RGB
br_cyan $Base1_RGB
br_white $Base3_RGB
fg $fg
bg $bg
bold $fg
selfg $Base2_RGB
selbg $Base01_RGB
curfg $cursor
curbg $cursor
link $Cyan_RGB
EOL
printf "%s1337;CursorShape=2%s" "$_OSC" "$_ST" # set cursor shape to underline
}
# 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
printf "%s4;%s;rgb:%s/%s/%s%s" "$_OSC" "$c" "${rgb:0:2}" "${rgb:2:2}" "${rgb:4:2}" "$_ST"
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
printf "%s%s;rgb:%s/%s/%s%s" "$_OSC" "$Ps" "${rgb:0:2}" "${rgb:2:2}" "${rgb:4:2}" "$_ST"
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}"
_source_extra_configs() {
local configs=(
/usr/local/etc/profile.d/bash_completion.sh
/usr/share/bash-completion/bash_completion
$LOCAL_CONFIG/bash/*
)
local f
for f in ${configs[@]}; do [ -f "$f" ] && source "$f"; done
}
_source_extra_configs
true