280 lines
6.8 KiB
Bash
Executable File
280 lines
6.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# ---
|
||
# @file_name: prompt.sh
|
||
# @description: a bash prompt
|
||
# @date: 2025-11-12
|
||
# @version: 1.0.1
|
||
# @usage: . prompt.sh
|
||
#
|
||
# @author: Jamie Albert
|
||
# @author_contact: <mailto:jamie.albert@flatmail.me
|
||
# @license: GNU Affero General Public License v3.0 (Included in LICENSE)
|
||
# Copyright (C) 2025, Jamie Albert
|
||
# ---
|
||
|
||
# ---
|
||
# Script Exports
|
||
# ---
|
||
declare -x PASSWORD_STORE_DIR=~/dao/storage/pass
|
||
# declare -x BW_SESSION; BW_SESSION=$(pass show bw/session)
|
||
|
||
# ---
|
||
# Script globals
|
||
# ---
|
||
declare -g _cached_uh=""
|
||
declare -g _uh_cache_key=""
|
||
declare -g _cached_pyenv_version=""
|
||
declare -g _pyenv_cache_key=""
|
||
declare -g _cached_readonly=""
|
||
declare -g _readonly_cache_key=""
|
||
|
||
# ---
|
||
# Shell options configuration
|
||
# ---
|
||
shopt -s histappend
|
||
shopt -s cmdhist
|
||
shopt -s histreedit
|
||
shopt -s histverify
|
||
shopt -s interactive_comments
|
||
shopt -s checkwinsize
|
||
shopt -s globstar
|
||
shopt -s nocaseglob
|
||
shopt -s dirspell
|
||
shopt -s cdspell
|
||
shopt -u autocd
|
||
|
||
if [[ $- =~ "i" ]]; then
|
||
bind "set completion-ignore-case on"
|
||
bind "set show-all-if-ambiguous on"
|
||
bind "set mark-symlinked-directories on"
|
||
fi
|
||
|
||
# ---
|
||
# * Symbols
|
||
# ---
|
||
_prompt_symbol="❯"
|
||
_git_symbol="git:"
|
||
_pyenv_symbol="pyenv:"
|
||
_readonly_symbol="ro:"
|
||
_screen_symbol="scr:"
|
||
|
||
# ---
|
||
# * Colours
|
||
# ---
|
||
_prompt_success_colour="142"
|
||
_prompt_fail_colour="203"
|
||
_prompt_user_colour="109"
|
||
_prompt_sudo_colour="208"
|
||
_prompt_at_colour="249"
|
||
_prompt_hostname_colour="132"
|
||
_prompt_info_colour="172"
|
||
_prompt_input_colour="254"
|
||
_prompt_dir_colour="249"
|
||
_git_module_colour="66"
|
||
_pyenv_module_colour="66"
|
||
_readonly_module_colour="196"
|
||
_screen_module_colour="33"
|
||
|
||
# ---
|
||
# * Miscellaneous
|
||
# ---
|
||
_prompt_hostname="ssh"
|
||
_prompt_separator=" "
|
||
_prompt_wrapper="[]"
|
||
|
||
# ---
|
||
# // * Nerd Symbols
|
||
# // OBSOLETE 2025-11-07
|
||
# ---
|
||
# _git_symbol=""
|
||
# _pyenv_symbol=""
|
||
# _readonly_symbol=""
|
||
# _screen_symbol=""
|
||
# _prompt_symbol=""
|
||
|
||
# ---
|
||
# * Aliases
|
||
# ---
|
||
alias count='find . -type f | wc -l'
|
||
alias cdd='cd /home/jamie/dao'
|
||
alias dnf='sudo dnf'
|
||
alias hist='history|grep'
|
||
alias ll="ls -laFh"
|
||
alias la='ls -A'
|
||
alias li='la | grep -i'
|
||
alias lh='ll -d .*'
|
||
alias mkdir='mkdir -p'
|
||
alias nano='nano -W'
|
||
alias qq='exit'
|
||
alias sc='sudo systemctl'
|
||
alias xclipc='xclip -sel c'
|
||
|
||
# ---
|
||
# * Environment settings
|
||
# ---
|
||
declare -g HISTTIMEFORMAT='%F %T '
|
||
declare -g PROMPT_DIRTRIM="2"
|
||
[[ -z "$LC_CTYPE" && -z "$LC_ALL" ]] && declare -g LC_CTYPE="${LANG%%:*}"
|
||
[[ -z "$HISTFILE" ]] && declare -g HISTFILE="$HOME/.bash_history"
|
||
declare -x HISTCONTROL=ignorespace
|
||
declare -x HISTFILESIZE=10000
|
||
declare -x HISTSIZE=${HISTFILESIZE}
|
||
|
||
# ---
|
||
# * colour function
|
||
# ---
|
||
_prompt_colour() {
|
||
[[ ${1} != "-" ]] && echo -ne "\[\033[38;5;${1}m\]" || echo -ne "\[\033[0m\]"
|
||
}
|
||
|
||
# ---
|
||
# * Generate prompt segments
|
||
# ---
|
||
_prompt_generate() {
|
||
declare _separator="" _text="${1%%|*}" _colour="${1##*|}"
|
||
[[ ${_prompt_seg} -gt 1 ]] && _separator="${_prompt_separator}"
|
||
_prompt_information+="${_separator}$(_prompt_colour "${_colour}")${_text}\[\e[0m\]"
|
||
((_prompt_seg++))
|
||
}
|
||
|
||
# ---
|
||
# * Screen
|
||
# ---
|
||
_screen_pre() {
|
||
[[ ${TERM} == "screen"* ]] && _prompt_generate "${_screen_symbol}|${_screen_module_colour}"
|
||
}
|
||
|
||
# ---
|
||
# * Git
|
||
# ---
|
||
_git_post() {
|
||
[[ -z "$_git_dir" ]] && _git_dir="$(git rev-parse --git-dir 2>/dev/null)"
|
||
[[ -n "$_git_dir" ]] || return
|
||
|
||
local _unsafe_ref
|
||
_unsafe_ref=$(git symbolic-ref -q HEAD 2>/dev/null) || return
|
||
local _clean_ref="${_unsafe_ref##refs/heads/}"
|
||
_clean_ref="${_clean_ref//[^a-zA-Z0-9\/]/-}"
|
||
|
||
local _status=""
|
||
[[ -n "$(git status --porcelain 2>/dev/null)" ]] && _status="*"
|
||
[[ -n "$(git ls-files --others --exclude-standard 2>/dev/null)" ]] && _status="${_status}+"
|
||
|
||
[[ -n ${_clean_ref} ]] && _prompt_generate "${_git_symbol} ${_clean_ref}${_status}|${_git_module_colour}"
|
||
}
|
||
|
||
# ---
|
||
# * Pyenv
|
||
# ---
|
||
_pyenv_post() {
|
||
[[ -n ${VIRTUAL_ENV} ]] || return
|
||
[[ "$VIRTUAL_ENV" != "$_pyenv_cache_key" ]] && {
|
||
_cached_pyenv_version="${PYTHON_VERSION}"
|
||
[[ -z ${_cached_pyenv_version} ]] && _cached_pyenv_version="$(python3 --version 2>/dev/null)"
|
||
_cached_pyenv_version="${_cached_pyenv_version#Python }"
|
||
_pyenv_cache_key="$VIRTUAL_ENV"
|
||
}
|
||
[[ -n ${_cached_pyenv_version} ]] && _prompt_generate "${_prompt_wrapper:0:1}${_pyenv_symbol} ${_cached_pyenv_version}${_prompt_wrapper:1:1}|${_pyenv_module_colour}"
|
||
}
|
||
|
||
# ---
|
||
# * Readonly
|
||
# ---
|
||
_readonly_post() {
|
||
[[ "$PWD" != "$_readonly_cache_key" ]] && {
|
||
_cached_readonly=""
|
||
[[ ! -w "$(pwd)" ]] && _cached_readonly="readonly"
|
||
_readonly_cache_key="$PWD"
|
||
}
|
||
[[ -n "$_cached_readonly" ]] && _prompt_generate "${_prompt_wrapper:0:1}${_readonly_symbol}${_prompt_wrapper:1:1}|${_readonly_module_colour}"
|
||
}
|
||
|
||
# ---
|
||
# * Build the main prompt
|
||
# ---
|
||
_prompt_build() {
|
||
declare _last_status="$?" _gen_uh _cache_key="${PWD}"
|
||
declare -gi _prompt_seg=1
|
||
|
||
[[ "$_cache_key" != "$_last_cache_key" ]] && {
|
||
unset _git_dir _cached_pyenv_version
|
||
_last_cache_key="$_cache_key"
|
||
}
|
||
|
||
# ---
|
||
# ! Insert *pre* functions here
|
||
# ---
|
||
# START
|
||
_screen_pre
|
||
# END
|
||
|
||
# ---
|
||
# * User and hostname
|
||
# ---
|
||
declare _user_colour="${_prompt_user_colour}"
|
||
sudo -nv 2>/dev/null && _user_colour="${_prompt_sudo_colour}"
|
||
|
||
_gen_uh="${_cached_uh}"
|
||
_uh_cache_key="${_prompt_hostname}:${SSH_CLIENT:-}:$(sudo -n -v 2>/dev/null && echo 'sudo' || echo 'nosudo')"
|
||
|
||
[[ "$_uh_cache_key" != "$_last_uh_key" ]] && {
|
||
_gen_uh="$(_prompt_colour "${_user_colour}")${USER}"
|
||
|
||
if [[ ${_prompt_hostname} == "all" ]] || [[ ${_prompt_hostname} == "ssh" && -n ${SSH_CLIENT} ]]; then
|
||
_gen_uh+="$(_prompt_colour "${_prompt_at_colour}")@$(_prompt_colour "${_prompt_hostname_colour}")${HOSTNAME}"
|
||
fi
|
||
|
||
_gen_uh+="\[\033[0m\]"
|
||
_cached_uh="$_gen_uh"
|
||
_last_uh_key="$_uh_cache_key"
|
||
}
|
||
_prompt_generate "${_gen_uh}|${_prompt_info_colour}"
|
||
|
||
# ---
|
||
# * Current directory
|
||
# ---
|
||
declare _current_dir="${PWD}"
|
||
_current_dir="${_current_dir/#$HOME/\~}"
|
||
_prompt_generate "$(_prompt_colour "${_prompt_info_colour}")${_prompt_wrapper:0:1}$(_prompt_colour "${_prompt_dir_colour}")${_current_dir}$(_prompt_colour "${_prompt_info_colour}")${_prompt_wrapper:1:1}\[\033[0m\]|${_prompt_info_colour}"
|
||
|
||
# ---
|
||
# * Error status
|
||
# ---
|
||
[[ ${_last_status} -ne 0 ]] && _prompt_generate "${_prompt_wrapper:0:1}${_last_status}${_prompt_wrapper:1:1}|${_prompt_fail_colour}"
|
||
|
||
# ---
|
||
# ! Insert *post* functions here
|
||
# ---
|
||
# START
|
||
_git_post
|
||
_pyenv_post
|
||
_readonly_post
|
||
|
||
# END
|
||
|
||
# ---
|
||
# *Final prompt symbol
|
||
# ---
|
||
_prompt_status_colour=${_prompt_success_colour}
|
||
[[ ${_last_status} -ne 0 ]] && _prompt_status_colour=${_prompt_fail_colour}
|
||
_prompt_information+="$(_prompt_colour "${_prompt_status_colour}")\n${_prompt_symbol}\[\e[0m\]"
|
||
PS1="${_prompt_information} "
|
||
unset _prompt_information _prompt_seg
|
||
}
|
||
|
||
# ---
|
||
# * Initialize prompt
|
||
# ---
|
||
_prompt_init() {
|
||
case "$PROMPT_COMMAND" in
|
||
*"_prompt_build"*) ;;
|
||
"") PROMPT_COMMAND="_prompt_build" ;;
|
||
*) PROMPT_COMMAND="_prompt_build;${PROMPT_COMMAND}" ;;
|
||
esac
|
||
}
|
||
|
||
# ---
|
||
# * Initialize when sourced
|
||
# ---
|
||
[[ ${BASH_SOURCE[0]} != "${0}" ]] && _prompt_init
|