# ========================= # 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 \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