Files
infra/dotfiles/common/.bashrc
2026-03-15 23:18:52 +01:00

317 lines
6.6 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =========================
# Portable Bash config
# Target: Void Linux + FreeBSD
# =========================
# Exit if not interactive
[[ $- != *i* ]] && return
# --- environment detection
case "$(uname -s)" in
Linux) PLATFORM="linux" ;;
FreeBSD) PLATFORM="freebsd" ;;
*) PLATFORM="other" ;;
esac
export PLATFORM
# --- history
HISTSIZE=10000
HISTFILESIZE=20000
HISTCONTROL=ignoredups:erasedups
HISTIGNORE='ls:ll:la:l:pwd:exit:clear:history'
HISTTIMEFORMAT=
shopt -s histappend
shopt -s checkwinsize
__history_sync() {
history -a
history -c
history -r
}
# --- shell options
set -o emacs
shopt -s cmdhist
# --- PATH
[ -d "$HOME/.local/bin" ] && PATH="$HOME/.local/bin:$PATH"
[ -d "$HOME/bin" ] && PATH="$HOME/bin:$PATH"
export PATH
# =========================
# Aliases (portable)
# =========================
if ls --color=auto >/dev/null 2>&1; then
alias ls='ls --color=auto'
else
alias ls='ls -G'
fi
alias l='ls'
alias ll='ls -lh'
alias la='ls -lah'
if grep --color=auto "" /dev/null >/dev/null 2>&1; then
alias grep='grep --color=auto'
fi
alias ..='cd ..'
alias ...='cd ../..'
alias cls='clear'
alias cp='cp -i'
alias mv='mv -i'
alias rm='rm -i'
# Git
alias g='git'
alias ga='git add'
alias gb='git branch'
alias gc='git commit'
alias gca='git commit -a'
alias gco='git checkout'
alias gd='git diff'
alias gl='git pull'
alias gp='git push'
alias gs='git status -sb'
alias glog='git log --oneline --decorate --graph -20'
# =========================
# Git prompt helpers
# =========================
__git_branch() {
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 1
command git symbolic-ref --quiet --short HEAD 2>/dev/null && return
command git rev-parse --short HEAD 2>/dev/null && return
return 1
}
__git_flags() {
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 1
local flags=""
git diff --no-ext-diff --quiet --exit-code 2>/dev/null || flags="${flags}*"
git diff --cached --no-ext-diff --quiet --exit-code 2>/dev/null || flags="${flags}+"
[ -n "$(git ls-files --others --exclude-standard 2>/dev/null)" ] && flags="${flags}?"
printf '%s' "$flags"
}
# =========================
# Colors
# =========================
if [ -t 1 ]; then
C_RESET='\[\033[0m\]'
C_USER='\[\033[1;97m\]'
C_HOST='\[\033[38;5;250m\]'
C_PATH='\[\033[1;96m\]'
C_GIT='\[\033[38;5;197m\]'
C_GIT_FLAG='\[\033[38;5;204m\]'
C_VENV='\[\033[38;5;177m\]'
C_CONT='\[\033[38;5;208m\]'
C_OK='\[\033[38;5;46m\]'
C_ERR='\[\033[38;5;196m\]'
C_DIM='\[\033[38;5;240m\]'
else
C_RESET=''
C_USER=''
C_HOST=''
C_PATH=''
C_GIT=''
C_GIT_FLAG=''
C_VENV=''
C_CONT=''
C_OK=''
C_ERR=''
C_DIM=''
fi
# =========================
# Prompt helpers
# =========================
__prompt_git() {
local branch flags
branch="$(__git_branch)" || return 0
flags="$(__git_flags)"
if [ -n "$flags" ]; then
printf ' %s<%s%s:%s%s>%s' \
"$C_GIT" "$branch" "$C_DIM" "$C_GIT_FLAG" "$flags" "$C_RESET"
else
printf ' %s<%s>%s' "$C_GIT" "$branch" "$C_RESET"
fi
}
__prompt_venv() {
[ -n "${VIRTUAL_ENV-}" ] || return 0
printf ' %s(%s)%s' "$C_VENV" "${VIRTUAL_ENV##*/}" "$C_RESET"
}
__prompt_container() {
local marker=""
if [ -f /run/.containerenv ]; then
marker="ctr"
elif [ -f /.dockerenv ]; then
marker="docker"
elif [ -n "${container-}" ]; then
marker="$container"
elif [ -n "${debian_chroot-}" ]; then
marker="$debian_chroot"
fi
[ -n "$marker" ] || return 0
printf ' %s[%s]%s' "$C_CONT" "$marker" "$C_RESET"
}
# =========================
# Prompt
# =========================
__set_prompt() {
local last_status="$1"
local host_part symbol status_color
if [ -n "${SSH_CONNECTION-}" ] || [ -n "${SSH_CLIENT-}" ]; then
host_part="${C_USER}\u${C_DIM}@${C_HOST}\h${C_RESET}"
else
host_part="${C_USER}\u${C_RESET}"
fi
if [ "${EUID:-$(id -u)}" -eq 0 ]; then
symbol="#"
else
symbol=""
fi
if [ "$last_status" -eq 0 ]; then
status_color="${C_OK}"
else
status_color="${C_ERR}"
fi
PS1="${host_part}${C_DIM}:${C_RESET}${C_PATH}\w${C_RESET}$(__prompt_venv)$(__prompt_container)$(__prompt_git) ${status_color}${symbol}${C_RESET} "
}
__prompt_command() {
local last_status=$?
__history_sync
__set_prompt "$last_status"
}
PROMPT_COMMAND="__prompt_command"
# =========================
# Readline / history search
# =========================
bind '"\e[A": history-search-backward'
bind '"\e[B": history-search-forward'
bind '"\e[1;5C": forward-word'
bind '"\e[1;5D": backward-word'
bind '"\e[5C": forward-word'
bind '"\e[5D": backward-word'
# =========================
# fzf history on Ctrl-r
# =========================
if command -v fzf >/dev/null 2>&1; then
__fzf_history() {
local selected history_data
if command -v tac >/dev/null 2>&1; then
history_data="$(
builtin history \
| sed 's/^[[:space:]]*[0-9][0-9]*[[:space:]]*//' \
| awk '!seen[$0]++' \
| awk 'NF' \
| tac
)"
else
history_data="$(
builtin history \
| sed 's/^[[:space:]]*[0-9][0-9]*[[:space:]]*//' \
| awk '!seen[$0]++' \
| awk 'NF' \
| tail -r
)"
fi
selected="$(printf '%s\n' "$history_data" | fzf --height 40% --layout=reverse --border --prompt='history> ')" || return
READLINE_LINE=$selected
READLINE_POINT=${#READLINE_LINE}
}
bind -x '"\C-r":__fzf_history'
fi
# =========================
# Completion
# =========================
for bc in \
/usr/share/bash-completion/bash_completion \
/usr/local/share/bash-completion/bash_completion \
/etc/bash_completion
do
if [ -r "$bc" ]; then
. "$bc"
break
fi
done
# =========================
# Portable helpers
# =========================
mkcd() {
[ $# -eq 1 ] || return 1
mkdir -p -- "$1" && cd -- "$1" || return
}
extract() {
[ $# -eq 1 ] || {
printf 'usage: extract <archive>\n' >&2
return 1
}
[ -f "$1" ] || {
printf 'extract: file not found: %s\n' "$1" >&2
return 1
}
case "$1" in
*.tar.bz2|*.tbz2) tar xjf "$1" ;;
*.tar.gz|*.tgz) tar xzf "$1" ;;
*.tar.xz|*.txz) tar xJf "$1" ;;
*.tar) tar xf "$1" ;;
*.bz2) bunzip2 "$1" ;;
*.gz) gunzip "$1" ;;
*.xz) unxz "$1" ;;
*.zip) unzip "$1" ;;
*.7z) 7z x "$1" ;;
*) printf 'extract: unsupported archive: %s\n' "$1" >&2; return 1 ;;
esac
}
# =========================
# OS-specific small touches
# =========================
if [ "$PLATFORM" = "freebsd" ]; then
alias df='df -h'
alias du='du -h'
elif [ "$PLATFORM" = "linux" ]; then
alias df='df -h'
alias du='du -h'
fi