moved helpers separately
This commit is contained in:
+3
-247
@@ -34,74 +34,11 @@
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
load_conf "prompt"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Colour variable names defined by disp.sh. They are the only names a theme or
|
||||
# the [prompt] configuration may reference (as $Name or ${Name}), and the only
|
||||
# palette variables a theme may redefine.
|
||||
_PROMPT_COLOR_NAMES=(
|
||||
Black Red Green Yellow Blue Purple Cyan White
|
||||
BBlack BRed BGreen BYellow BBlue BPurple BCyan BWhite
|
||||
UBlack URed UGreen UYellow UBlue UPurple UCyan UWhite
|
||||
On_Black On_Red On_Green On_Yellow On_Blue On_Purple On_Cyan On_White
|
||||
IBlack IRed IGreen IYellow IBlue IPurple ICyan IWhite
|
||||
BIBlack BIRed BIGreen BIYellow BIBlue BIPurple BICyan BIWhite
|
||||
On_IBlack On_IRed On_IGreen On_IYellow On_IBlue On_IPurple On_ICyan On_IWhite
|
||||
DEFAULTFG DEFAULTBG DEFAULTCOL RESETCOL
|
||||
)
|
||||
# The same names as an ERE alternation (Black|Red|...)
|
||||
_PROMPT_COLOR_RE=""
|
||||
for _pc_name in "${_PROMPT_COLOR_NAMES[@]}"; do
|
||||
_PROMPT_COLOR_RE+="|${_pc_name}"
|
||||
done
|
||||
_PROMPT_COLOR_RE="${_PROMPT_COLOR_RE#|}"
|
||||
unset _pc_name
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Check a colour value and put its resolved form in _PROMPT_RESOLVED.
|
||||
# A value is a sequence of blocks, each one either
|
||||
# $ColorName or ${ColorName} — colour variable from disp.sh (resolved by
|
||||
# indirection, never evaluated)
|
||||
# \e[...m or \033[...m — raw ANSI escape literal
|
||||
# Anything else is refused (return 1): colours end up inside PS1, so they must
|
||||
# not be able to carry anything else than colour codes.
|
||||
# Usage: _prompt_resolve_color <value>
|
||||
_prompt_resolve_color()
|
||||
{
|
||||
local rest="$1" out="" name
|
||||
local ref_re='^\$(\{('"$_PROMPT_COLOR_RE"')\}|('"$_PROMPT_COLOR_RE"'))'
|
||||
local ansi_re='^(\\e|\\033)\[[0-9;]*m'
|
||||
|
||||
[[ -n $rest ]] || return 1
|
||||
while [[ -n $rest ]]; do
|
||||
if [[ $rest =~ $ref_re ]]; then
|
||||
name="${BASH_REMATCH[2]:-${BASH_REMATCH[3]}}"
|
||||
out+="${!name:-}"
|
||||
elif [[ $rest =~ $ansi_re ]]; then
|
||||
out+="${BASH_REMATCH[0]}"
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
rest="${rest:${#BASH_REMATCH[0]}}"
|
||||
done
|
||||
_PROMPT_RESOLVED="$out"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Path of the theme file for a bare name (searched in the theme directory) or an
|
||||
# explicit path (anything containing a slash).
|
||||
# Usage: _prompt_theme_file <theme_name_or_path> [theme_dir]
|
||||
_prompt_theme_file()
|
||||
{
|
||||
local name="$1" dir="${2:-${PROMPT_THEME_DIR:-$MYPATH/profile.d/themes}}"
|
||||
if [[ "$name" == */* ]]; then
|
||||
printf '%s' "$name"
|
||||
else
|
||||
printf '%s' "$dir/${name}.theme"
|
||||
fi
|
||||
}
|
||||
# Common helpers, then the ones private to this module (helpers/prompt.sh)
|
||||
declare -F _profile_load_helpers >/dev/null || . "$(dirname -- "${BASH_SOURCE[0]}")/../helpers/common.sh"
|
||||
_profile_load_helpers "${BASH_SOURCE[0]}"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Parse a prompt theme file safely — it is NEVER sourced or executed.
|
||||
@@ -192,59 +129,6 @@ load_theme()
|
||||
}
|
||||
# Not exported, it remains private (like the other _prompt_* helpers: set_theme
|
||||
# and set_prompt are meant to be used from the interactive shell itself).
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Apply the PROMPT_COLOR_* keys of the [prompt] section on top of the current
|
||||
# colours, so they win over the theme. Their values may use $ColorName, which
|
||||
# parse_conf leaves untouched while the colour variables do not exist yet.
|
||||
# A value that is not a valid colour is reported and not applied.
|
||||
# Usage: _prompt_apply_overrides
|
||||
_prompt_apply_overrides()
|
||||
{
|
||||
declare -p CONF_prompt >/dev/null 2>&1 || return 0
|
||||
|
||||
local k
|
||||
for k in "${!CONF_prompt[@]}"; do
|
||||
[[ $k == PROMPT_COLOR_* ]] || continue
|
||||
if _prompt_resolve_color "${CONF_prompt[$k]}"; then
|
||||
export "$k=$_PROMPT_RESOLVED"
|
||||
else
|
||||
printf "[ Warning ] [prompt] %s: invalid colour value '%s', ignoring.\n" \
|
||||
"$k" "${CONF_prompt[$k]}" >&2
|
||||
# load_conf exported the raw text: do not keep it as a colour
|
||||
[[ "${!k:-}" == "${CONF_prompt[$k]}" ]] && unset "$k"
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Switch to a theme from a clean state: default palette, no PROMPT_COLOR_*
|
||||
# left over from the previous theme (a partial theme must not inherit them),
|
||||
# the theme, then the [prompt] overrides. The theme file is checked first, so a
|
||||
# wrong name changes nothing.
|
||||
# Usage: _prompt_load_theme_clean <theme_name_or_path> [theme_dir]
|
||||
_prompt_load_theme_clean()
|
||||
{
|
||||
local file v
|
||||
file=$(_prompt_theme_file "$1" "${2:-}")
|
||||
if [[ ! -f "$file" || ! -r "$file" ]]; then
|
||||
printf "[ Warning ] set_theme: theme file not found: %s\n" "$file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
set_colors
|
||||
for v in ${!PROMPT_COLOR_@}; do
|
||||
unset "$v"
|
||||
done
|
||||
load_theme "$1" "${2:-}" || return 1
|
||||
_prompt_apply_overrides
|
||||
}
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Dynamically switch the prompt theme for the current shell session.
|
||||
# Calls load_theme to apply the new colour values immediately, then updates
|
||||
@@ -419,34 +303,11 @@ set_theme()
|
||||
disp I "Prompt theme set to $theme_name."
|
||||
}
|
||||
export -f set_theme
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# timer_* functions : internal timing functions for the prompt.
|
||||
# The start is recorded by the DEBUG trap (profile.sh) before each command and
|
||||
# the elapsed time is computed by set_prompt, through PROMPT_COMMAND.
|
||||
|
||||
# Put the current time, in microseconds since the epoch, in _timer_us.
|
||||
# EPOCHREALTIME (bash >= 5) costs no process; its decimal separator follows the
|
||||
# locale ("." or ","), hence the removal of both. Otherwise "date +%s%N" is
|
||||
# used (it prints a literal "N" where nanoseconds are not supported, which the
|
||||
# digit check rejects), then plain seconds.
|
||||
_timer_now()
|
||||
{
|
||||
if [[ -n "${EPOCHREALTIME:-}" ]]; then
|
||||
_timer_us="${EPOCHREALTIME//[.,]/}"
|
||||
else
|
||||
local t
|
||||
t=$(date +%s%N 2>/dev/null)
|
||||
if [[ $t =~ ^[0-9]{16,}$ ]]; then
|
||||
_timer_us=$(( t / 1000 ))
|
||||
else
|
||||
_timer_us=$(( $(date +%s) * 1000000 ))
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Usage: timer_start
|
||||
# Record the start time of the command about to run, unless already recorded
|
||||
# (the DEBUG trap fires for every simple command of a pipeline or function: only
|
||||
@@ -498,107 +359,6 @@ timer_stop()
|
||||
# definition resets $?, and set_prompt must read the exit status of the user's
|
||||
# last command before anything else runs.
|
||||
|
||||
_prompt_seg_git()
|
||||
{
|
||||
_PROMPT_SEG=""
|
||||
# Fast path: skip git lookup when feature is disabled.
|
||||
[[ "${PROMPT_SHOW_GIT:-1}" == "0" ]] && return 0
|
||||
|
||||
local branch
|
||||
branch=$(git symbolic-ref --quiet --short HEAD 2>/dev/null) || \
|
||||
branch=$(git rev-parse --short HEAD 2>/dev/null) || return 0
|
||||
|
||||
local dirty="" sync="" timed_out=0
|
||||
|
||||
if [[ "${PROMPT_SHOW_GIT_STATUS:-1}" != "0" ]]; then
|
||||
# Build a timeout wrapper if the 'timeout' command is available;
|
||||
# fall back to direct execution on systems that lack it.
|
||||
local -a _tw=()
|
||||
command -v timeout >/dev/null 2>&1 && _tw=(timeout "${PROMPT_GIT_TIMEOUT:-2}")
|
||||
|
||||
# One call for everything: --branch gives the "# branch.ab +A -B" line
|
||||
# (only when an upstream exists) and each changed tracked file gives a
|
||||
# line starting with 1, 2 or u. Untracked files are not counted.
|
||||
# GIT_OPTIONAL_LOCKS=0 keeps git from taking the index lock to refresh
|
||||
# it, which would make a concurrent "git commit" fail.
|
||||
local out ec
|
||||
out=$(GIT_OPTIONAL_LOCKS=0 "${_tw[@]}" git status --porcelain=v2 --branch \
|
||||
--untracked-files=no --ignore-submodules 2>/dev/null)
|
||||
ec=$?
|
||||
if [[ $ec -eq 124 ]]; then
|
||||
timed_out=1
|
||||
else
|
||||
[[ $'\n'"$out" == *$'\n'[12u]\ * ]] && dirty="*"
|
||||
if [[ "$out" =~ \#\ branch\.ab\ \+([0-9]+)\ -([0-9]+) ]]; then
|
||||
if [[ "${BASH_REMATCH[1]}" -gt 0 || "${BASH_REMATCH[2]}" -gt 0 ]]; then
|
||||
sync=" +${BASH_REMATCH[1]}/-${BASH_REMATCH[2]}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $timed_out -eq 1 ]]; then
|
||||
_PROMPT_SEG="git:${branch}?"
|
||||
else
|
||||
_PROMPT_SEG="git:${branch}${dirty}${sync}"
|
||||
fi
|
||||
}
|
||||
|
||||
_prompt_seg_conda()
|
||||
{
|
||||
_PROMPT_SEG=""
|
||||
[[ "${PROMPT_SHOW_CONDA:-1}" == "0" ]] && return 0
|
||||
[[ -z "${CONDA_DEFAULT_ENV:-}" ]] && return 0
|
||||
_PROMPT_SEG="conda:${CONDA_DEFAULT_ENV}"
|
||||
}
|
||||
|
||||
_prompt_seg_venv()
|
||||
{
|
||||
_PROMPT_SEG=""
|
||||
[[ "${PROMPT_SHOW_VENV:-1}" == "0" ]] && return 0
|
||||
[[ -n "${CONDA_DEFAULT_ENV:-}" ]] && return 0
|
||||
[[ -z "${VIRTUAL_ENV:-}" ]] && return 0
|
||||
_PROMPT_SEG="venv:${VIRTUAL_ENV##*/}"
|
||||
}
|
||||
|
||||
_prompt_seg_session()
|
||||
{
|
||||
_PROMPT_SEG=""
|
||||
[[ "${PROMPT_SHOW_SESSION:-1}" == "0" ]] && return 0
|
||||
|
||||
local -a tags=()
|
||||
[[ -n "${SSH_CONNECTION:-}" ]] && tags+=("ssh")
|
||||
[[ -n "${TMUX:-}" ]] && tags+=("tmux")
|
||||
[[ -n "${STY:-}" ]] && tags+=("screen")
|
||||
[[ ${#tags[@]} -eq 0 ]] && return 0
|
||||
|
||||
local out="${tags[0]}" i
|
||||
for ((i=1; i<${#tags[@]}; ++i)); do
|
||||
out+="+${tags[i]}"
|
||||
done
|
||||
_PROMPT_SEG="$out"
|
||||
}
|
||||
|
||||
# Append the current _PROMPT_SEG to the context text _PROMPT_CTX (" | " between
|
||||
# segments). An "if" keeps the status at 0 when the segment is empty.
|
||||
_prompt_ctx_add()
|
||||
{
|
||||
if [[ -n "$_PROMPT_SEG" ]]; then
|
||||
if [[ -n "$_PROMPT_CTX" ]]; then
|
||||
_PROMPT_CTX+=" | $_PROMPT_SEG"
|
||||
else
|
||||
_PROMPT_CTX="$_PROMPT_SEG"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Store the exit status of the user's last command (first command of a
|
||||
# PROMPT_COMMAND that also contains other commands, see profile.sh).
|
||||
_profile_save_status()
|
||||
{
|
||||
_profile_status=$?
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Function triggered internally by bash : defining prompt
|
||||
# Usage: set_prompt
|
||||
@@ -680,9 +440,6 @@ set_prompt()
|
||||
# Print the working directory and prompt marker, then reset colour.
|
||||
PS1+="\[${_dir_fg}\]\\w \\\$\[$RESETCOL\] "
|
||||
}
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Theme and configuration loading.
|
||||
# Precedence (lowest → highest):
|
||||
@@ -703,5 +460,4 @@ unset _pt_theme _pt_dir
|
||||
_prompt_apply_overrides
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# EOF
|
||||
|
||||
Reference in New Issue
Block a user