prompt bug fix
This commit is contained in:
@@ -396,6 +396,11 @@ PROMPT_COLOR_USER_FG = $ICyan
|
|||||||
PROMPT_COLOR_DIR_FG = $IYellow
|
PROMPT_COLOR_DIR_FG = $IYellow
|
||||||
```
|
```
|
||||||
|
|
||||||
|
A value is one or more blocks, each a colour variable (`$ICyan`, `${ICyan}`) or a
|
||||||
|
raw ANSI literal (`\e[1;32m`, `\033[4m`), e.g. `$BWhite\e[4m`; anything else is
|
||||||
|
rejected with a warning (colours end up in `PS1`). These overrides always win over
|
||||||
|
the theme, also after `set_theme`.
|
||||||
|
|
||||||
The twelve available `PROMPT_COLOR_*` keys are:
|
The twelve available `PROMPT_COLOR_*` keys are:
|
||||||
|
|
||||||
| Key | Role |
|
| Key | Role |
|
||||||
|
|||||||
@@ -119,6 +119,20 @@ Versions follow `MAJOR.MINOR.PATCH-REVISION_STAGE_N` (e.g. `3.99.1-4_rc_1`).
|
|||||||
child, validates the PID and refuses the current shell; `ppn` matched PIDs
|
child, validates the PID and refuses the current shell; `ppn` matched PIDs
|
||||||
and names such as `kde-bash` (now exact); `ppg`/`gpid` fallbacks no longer
|
and names such as `kde-bash` (now exact); `ppg`/`gpid` fallbacks no longer
|
||||||
match their own `awk`; `PPU_DEFAULT_FORMAT` documented with its real value.
|
match their own `awk`; `PPU_DEFAULT_FORMAT` documented with its real value.
|
||||||
|
- `prompt.sh` (security): a git branch, conda environment or virtualenv named
|
||||||
|
like `x$(command)` was **executed** each time the prompt was drawn, because the
|
||||||
|
names were copied into `PS1`; the context segment is now referenced as a
|
||||||
|
variable and never re-expanded.
|
||||||
|
- `prompt.sh`: the exit status shown in the prompt was always `0` (the nested
|
||||||
|
function definitions at the top of `set_prompt` reset `$?`; they are now
|
||||||
|
defined once at load time); `PROMPT_COLOR_*` overrides of the `[prompt]`
|
||||||
|
section never beat the theme and `$ColorName` values were emptied by
|
||||||
|
`parse_conf` in a fresh login shell (now resolved, validated, and re-applied
|
||||||
|
after `set_theme`); `set_theme --preview` left the previewed colours behind
|
||||||
|
when none were set before, and a switch to a partial theme kept the previous
|
||||||
|
theme's colours; the prompt no longer forks `date` twice per command
|
||||||
|
(`$EPOCHREALTIME`) and runs one `git status` instead of three git commands,
|
||||||
|
without taking the index lock.
|
||||||
- `compress.sh`: option flags and loop variables no longer leak into the
|
- `compress.sh`: option flags and loop variables no longer leak into the
|
||||||
interactive shell.
|
interactive shell.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ project and will not be addressed in Bash.
|
|||||||
stops when the prompt reappears; in Windows Terminal, timer events appear tied to prompt
|
stops when the prompt reappears; in Windows Terminal, timer events appear tied to prompt
|
||||||
display rather than to the Enter keypress.
|
display rather than to the Enter keypress.
|
||||||
- **Cause:** Execution time is measured via a `DEBUG` trap and `PROMPT_COMMAND` using
|
- **Cause:** Execution time is measured via a `DEBUG` trap and `PROMPT_COMMAND` using
|
||||||
`date +%s%N` deltas. WSL + Windows Terminal introduces scheduling jitter between Bash signal
|
`$EPOCHREALTIME` (or `date +%s%N` on bash < 5) deltas. WSL + Windows Terminal introduces scheduling jitter between Bash signal
|
||||||
events and the underlying Windows terminal layer that does not match wall-clock perception.
|
events and the underlying Windows terminal layer that does not match wall-clock perception.
|
||||||
- **Impact:** Cosmetic / observability only — commands execute normally.
|
- **Impact:** Cosmetic / observability only — commands execute normally.
|
||||||
- **Status:** Not fixable in Bash; this is a limitation of the Windows Terminal / WSL
|
- **Status:** Not fixable in Bash; this is a limitation of the Windows Terminal / WSL
|
||||||
|
|||||||
+269
-181
@@ -34,19 +34,83 @@
|
|||||||
# * OF SUCH DAMAGE.
|
# * OF SUCH DAMAGE.
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
load_conf "prompt"
|
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
|
||||||
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Parse a prompt theme file safely — it is NEVER sourced or executed.
|
# Parse a prompt theme file safely — it is NEVER sourced or executed.
|
||||||
# Two categories of keys are accepted:
|
# Two categories of keys are accepted:
|
||||||
# PROMPT_COLOR_* — prompt slot colours (TIME_FG, BAR_BG, …)
|
# PROMPT_COLOR_* — prompt slot colours (TIME_FG, BAR_BG, …)
|
||||||
# Standard colour variables from disp.sh (Blue, On_IBlack, …) — allows a
|
# Standard colour variables from disp.sh (Blue, On_IBlack, …) — allows a
|
||||||
# theme to redefine the palette used everywhere in the shell session.
|
# theme to redefine the palette used everywhere in the shell session.
|
||||||
# Allowed value forms:
|
# Values follow the forms accepted by _prompt_resolve_color. Any other key or
|
||||||
# $ColorName or ${ColorName} — colour variable from disp.sh (resolved by
|
# value is rejected with a warning.
|
||||||
# indirection via ${!varname})
|
|
||||||
# \e[...m or \033[...m — raw ANSI escape literal (single block)
|
|
||||||
# Any other key or value is rejected with a warning.
|
|
||||||
# Usage: load_theme <theme_name_or_path> [theme_dir]
|
# Usage: load_theme <theme_name_or_path> [theme_dir]
|
||||||
# theme_name_or_path : bare name (e.g. "dark") or an explicit path.
|
# theme_name_or_path : bare name (e.g. "dark") or an explicit path.
|
||||||
# theme_dir : directory to search for bare names; defaults to
|
# theme_dir : directory to search for bare names; defaults to
|
||||||
@@ -55,23 +119,18 @@ load_conf "prompt"
|
|||||||
load_theme()
|
load_theme()
|
||||||
{
|
{
|
||||||
local theme_name="$1"
|
local theme_name="$1"
|
||||||
local theme_dir="${2:-${PROMPT_THEME_DIR:-$MYPATH/profile.d/themes}}"
|
|
||||||
local theme_file=""
|
local theme_file=""
|
||||||
|
|
||||||
[[ -z "$theme_name" ]] && return 0
|
[[ -z "$theme_name" ]] && return 0
|
||||||
|
|
||||||
if [[ "$theme_name" == /* || "$theme_name" == */* ]]; then
|
theme_file=$(_prompt_theme_file "$theme_name" "${2:-}")
|
||||||
theme_file="$theme_name"
|
|
||||||
else
|
|
||||||
theme_file="$theme_dir/${theme_name}.theme"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -f "$theme_file" || ! -r "$theme_file" ]]; then
|
if [[ ! -f "$theme_file" || ! -r "$theme_file" ]]; then
|
||||||
printf "[ Warning ] load_theme: theme file not found: %s\n" "$theme_file" >&2
|
printf "[ Warning ] load_theme: theme file not found: %s\n" "$theme_file" >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ---- Key whitelist: prompt slots ----------------------------------------
|
# ---- Key whitelist: prompt slots and standard colour variables ----------
|
||||||
local -A _lth_allowed=(
|
local -A _lth_allowed=(
|
||||||
[PROMPT_COLOR_TIME_FG]=1 [PROMPT_COLOR_TIME_BG]=1
|
[PROMPT_COLOR_TIME_FG]=1 [PROMPT_COLOR_TIME_BG]=1
|
||||||
[PROMPT_COLOR_BAR_BG]=1
|
[PROMPT_COLOR_BAR_BG]=1
|
||||||
@@ -81,41 +140,13 @@ load_theme()
|
|||||||
[PROMPT_COLOR_DIR_FG]=1
|
[PROMPT_COLOR_DIR_FG]=1
|
||||||
[PROMPT_COLOR_CTX_FG]=1
|
[PROMPT_COLOR_CTX_FG]=1
|
||||||
)
|
)
|
||||||
|
|
||||||
# ---- Colour variable names exported by disp.sh --------------------------
|
|
||||||
local _lth_color_re
|
|
||||||
_lth_color_re='Black|Red|Green|Yellow|Blue|Purple|Cyan|White'
|
|
||||||
_lth_color_re+='|BBlack|BRed|BGreen|BYellow|BBlue|BPurple|BCyan|BWhite'
|
|
||||||
_lth_color_re+='|UBlack|URed|UGreen|UYellow|UBlue|UPurple|UCyan|UWhite'
|
|
||||||
_lth_color_re+='|On_Black|On_Red|On_Green|On_Yellow|On_Blue|On_Purple|On_Cyan|On_White'
|
|
||||||
_lth_color_re+='|IBlack|IRed|IGreen|IYellow|IBlue|IPurple|ICyan|IWhite'
|
|
||||||
_lth_color_re+='|BIBlack|BIRed|BIGreen|BIYellow|BIBlue|BIPurple|BICyan|BIWhite'
|
|
||||||
_lth_color_re+='|On_IBlack|On_IRed|On_IGreen|On_IYellow|On_IBlue|On_IPurple|On_ICyan|On_IWhite'
|
|
||||||
_lth_color_re+='|DEFAULTFG|DEFAULTBG|DEFAULTCOL|RESETCOL'
|
|
||||||
|
|
||||||
# ---- Key whitelist: standard colour vars (same list as above) -----------
|
|
||||||
local _lth_cn
|
local _lth_cn
|
||||||
for _lth_cn in \
|
for _lth_cn in "${_PROMPT_COLOR_NAMES[@]}"; do
|
||||||
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; do
|
|
||||||
_lth_allowed[$_lth_cn]=1
|
_lth_allowed[$_lth_cn]=1
|
||||||
done
|
done
|
||||||
unset _lth_cn
|
|
||||||
|
|
||||||
# ERE: safe colour reference $Name or ${Name}
|
|
||||||
local _lth_ref_re='^\$\{?('"$_lth_color_re"')\}?$'
|
|
||||||
|
|
||||||
# ERE: raw ANSI escape literal \e[...m or \033[...m
|
|
||||||
local _lth_ansi_re='^(\\e|\\033)\[[0-9;]*m$'
|
|
||||||
|
|
||||||
# ---- Line parser ---------------------------------------------------------
|
# ---- Line parser ---------------------------------------------------------
|
||||||
local _lth_line _lth_key _lth_value _lth_varname _lth_lineno=0
|
local _lth_line _lth_key _lth_value _lth_lineno=0
|
||||||
|
|
||||||
while IFS= read -r _lth_line || [[ -n "$_lth_line" ]]; do
|
while IFS= read -r _lth_line || [[ -n "$_lth_line" ]]; do
|
||||||
_lth_lineno=$(( _lth_lineno + 1 ))
|
_lth_lineno=$(( _lth_lineno + 1 ))
|
||||||
@@ -151,25 +182,68 @@ load_theme()
|
|||||||
_lth_value="${_lth_value%%\'*}"
|
_lth_value="${_lth_value%%\'*}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$_lth_value" =~ $_lth_ref_re ]]; then
|
if _prompt_resolve_color "$_lth_value"; then
|
||||||
# Safe colour variable reference — resolve via indirection
|
export "$_lth_key"="$_PROMPT_RESOLVED"
|
||||||
_lth_varname="${_lth_value#\$}"
|
|
||||||
_lth_varname="${_lth_varname#\{}"
|
|
||||||
_lth_varname="${_lth_varname%\}}"
|
|
||||||
export "$_lth_key"="${!_lth_varname}"
|
|
||||||
elif [[ "$_lth_value" =~ $_lth_ansi_re ]]; then
|
|
||||||
# Raw ANSI escape literal — accept as-is
|
|
||||||
export "$_lth_key"="$_lth_value"
|
|
||||||
else
|
else
|
||||||
printf "[ Warning ] load_theme: %s:%d: invalid value for '%s', ignoring.\n" \
|
printf "[ Warning ] load_theme: %s:%d: invalid value for '%s', ignoring.\n" \
|
||||||
"$theme_file" "$_lth_lineno" "$_lth_key" >&2
|
"$theme_file" "$_lth_lineno" "$_lth_key" >&2
|
||||||
fi
|
fi
|
||||||
done < "$theme_file"
|
done < "$theme_file"
|
||||||
}
|
}
|
||||||
# Not exported, it remains private
|
# 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.
|
# Dynamically switch the prompt theme for the current shell session.
|
||||||
@@ -204,7 +278,7 @@ set_theme()
|
|||||||
printf "\tset_theme \t— list available themes\n"
|
printf "\tset_theme \t— list available themes\n"
|
||||||
printf "\tset_theme dark \t— apply the dark theme\n"
|
printf "\tset_theme dark \t— apply the dark theme\n"
|
||||||
printf "\tset_theme -p dark \t— preview the dark theme\n"
|
printf "\tset_theme -p dark \t— preview the dark theme\n"
|
||||||
printf "\tset_theme -S \t— save current theme in config\n"
|
printf "\tset_theme -S \t— save the current theme to the configuration\n"
|
||||||
printf "\tset_theme -S dark \t— apply and save the dark theme\n"
|
printf "\tset_theme -S dark \t— apply and save the dark theme\n"
|
||||||
printf "\tset_theme ~/my.theme\t— apply a theme by path\n"
|
printf "\tset_theme ~/my.theme\t— apply a theme by path\n"
|
||||||
return 0
|
return 0
|
||||||
@@ -288,23 +362,19 @@ set_theme()
|
|||||||
|
|
||||||
# -- preview mode --------------------------------------------------------
|
# -- preview mode --------------------------------------------------------
|
||||||
if (( preview )); then
|
if (( preview )); then
|
||||||
local old_theme="${PROMPT_THEME:-}"
|
# Snapshot the palette and the prompt colours by value, to put back
|
||||||
local -a old_prompt_color_vars=()
|
# exactly what was there (including the PROMPT_COLOR_* that did not
|
||||||
|
# exist, which a previewed theme would otherwise leave behind).
|
||||||
|
local -A _snap=()
|
||||||
local _v
|
local _v
|
||||||
for _v in ${!PROMPT_COLOR_@}; do
|
for _v in "${_PROMPT_COLOR_NAMES[@]}" ${!PROMPT_COLOR_@}; do
|
||||||
old_prompt_color_vars+=("$_v=${!_v}")
|
[[ -n "${!_v+x}" ]] && _snap[$_v]="${!_v}"
|
||||||
done
|
done
|
||||||
|
|
||||||
set_colors
|
local _rc=0
|
||||||
load_theme "$theme_name" || {
|
_prompt_load_theme_clean "$theme_name" "$theme_dir" || _rc=1
|
||||||
set_colors
|
|
||||||
if [[ -n "$old_theme" ]]; then
|
|
||||||
load_theme "$old_theme" || true
|
|
||||||
export PROMPT_THEME="$old_theme"
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (( _rc == 0 )); then
|
||||||
printf "Preview for theme '%s':\n" "$theme_name"
|
printf "Preview for theme '%s':\n" "$theme_name"
|
||||||
printf "%b [ 13:37:00 ] %b%b [ 0 %b• (5s) %b] %b user@host%b [ git:main +1/-0 ] %b\n" \
|
printf "%b [ 13:37:00 ] %b%b [ 0 %b• (5s) %b] %b user@host%b [ git:main +1/-0 ] %b\n" \
|
||||||
"${PROMPT_COLOR_TIME_FG:-}${PROMPT_COLOR_TIME_BG:-}" "${DEFAULTCOL:-}" \
|
"${PROMPT_COLOR_TIME_FG:-}${PROMPT_COLOR_TIME_BG:-}" "${DEFAULTCOL:-}" \
|
||||||
@@ -322,23 +392,22 @@ set_theme()
|
|||||||
"${PROMPT_COLOR_CTX_FG:-}${PROMPT_COLOR_BAR_BG:-}" "${DEFAULTCOL:-}"
|
"${PROMPT_COLOR_CTX_FG:-}${PROMPT_COLOR_BAR_BG:-}" "${DEFAULTCOL:-}"
|
||||||
printf "%b/path/to/dir \$ %b\n" \
|
printf "%b/path/to/dir \$ %b\n" \
|
||||||
"${PROMPT_COLOR_DIR_FG:-}" "${DEFAULTCOL:-}"
|
"${PROMPT_COLOR_DIR_FG:-}" "${DEFAULTCOL:-}"
|
||||||
|
|
||||||
set_colors
|
|
||||||
if [[ -n "$old_theme" ]]; then
|
|
||||||
load_theme "$old_theme" || true
|
|
||||||
export PROMPT_THEME="$old_theme"
|
|
||||||
fi
|
fi
|
||||||
for _v in "${old_prompt_color_vars[@]}"; do
|
|
||||||
export "${_v%%=*}=${_v#*=}"
|
# Restore: every colour variable is either put back or removed
|
||||||
|
for _v in "${_PROMPT_COLOR_NAMES[@]}" ${!PROMPT_COLOR_@}; do
|
||||||
|
if [[ -n "${_snap[$_v]+x}" ]]; then
|
||||||
|
export "$_v=${_snap[$_v]}"
|
||||||
|
else
|
||||||
|
unset "$_v"
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
return 0
|
return "$_rc"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# -- apply mode ----------------------------------------------------------
|
# -- apply mode ----------------------------------------------------------
|
||||||
|
|
||||||
# Reset colours to defaults before loading the new theme
|
_prompt_load_theme_clean "$theme_name" "$theme_dir" || return 1
|
||||||
set_colors
|
|
||||||
load_theme "$theme_name" || return 1
|
|
||||||
|
|
||||||
export PROMPT_THEME="$theme_name"
|
export PROMPT_THEME="$theme_name"
|
||||||
if (( save )); then
|
if (( save )); then
|
||||||
@@ -354,30 +423,50 @@ export -f set_theme
|
|||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# timer_* functions : internal timing function for prompt
|
# timer_* functions : internal timing functions for the prompt.
|
||||||
# Usage: timer_now
|
# The start is recorded by the DEBUG trap (profile.sh) before each command and
|
||||||
# This function returns the current time in nanoseconds since the epoch. It
|
# the elapsed time is computed by set_prompt, through PROMPT_COMMAND.
|
||||||
# first tries to use the %N format specifier for nanoseconds, but if that is
|
|
||||||
# not supported (e.g., on older systems), it falls back to seconds.
|
# Put the current time, in microseconds since the epoch, in _timer_us.
|
||||||
function timer_now
|
# 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()
|
||||||
{
|
{
|
||||||
date +%s%N 2>/dev/null || date +%s
|
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
|
# Usage: timer_start
|
||||||
# This function initializes the timer_start variable with the current time in
|
# Record the start time of the command about to run, unless already recorded
|
||||||
# nanoseconds. It is used to measure the elapsed time for the prompt.
|
# (the DEBUG trap fires for every simple command of a pipeline or function: only
|
||||||
function timer_start
|
# the first one counts).
|
||||||
|
timer_start()
|
||||||
{
|
{
|
||||||
timer_start=${timer_start:-$(timer_now)}
|
if [[ -z "${_timer_start_us:-}" ]]; then
|
||||||
|
_timer_now
|
||||||
|
_timer_start_us="$_timer_us"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Usage: timer_stop
|
# Usage: timer_stop
|
||||||
# This function calculates the elapsed time since timer_start and formats it
|
# Compute the time elapsed since timer_start and format it into timer_show with
|
||||||
# into a human-readable string with appropriate units (us, ms, s, m, h
|
# an appropriate unit (us, ms, s, m, h).
|
||||||
function timer_stop
|
timer_stop()
|
||||||
{
|
{
|
||||||
local delta_us=$((($(timer_now) - timer_start) / 1000))
|
_timer_now
|
||||||
|
local delta_us=$(( _timer_us - ${_timer_start_us:-$_timer_us} ))
|
||||||
|
(( delta_us < 0 )) && delta_us=0
|
||||||
local us=$((delta_us % 1000))
|
local us=$((delta_us % 1000))
|
||||||
local ms=$(((delta_us / 1000) % 1000))
|
local ms=$(((delta_us / 1000) % 1000))
|
||||||
local s=$(((delta_us / 1000000) % 60))
|
local s=$(((delta_us / 1000000) % 60))
|
||||||
@@ -391,7 +480,7 @@ function timer_stop
|
|||||||
elif ((s >= 10)); then
|
elif ((s >= 10)); then
|
||||||
timer_show=${s}.$((ms / 100))s
|
timer_show=${s}.$((ms / 100))s
|
||||||
elif ((s > 0)); then
|
elif ((s > 0)); then
|
||||||
timer_show=${s}.$(printf %03d $ms)s
|
printf -v timer_show '%d.%03ds' "$s" "$ms"
|
||||||
elif ((ms >= 100)); then
|
elif ((ms >= 100)); then
|
||||||
timer_show=${ms}ms
|
timer_show=${ms}ms
|
||||||
elif ((ms > 0)); then
|
elif ((ms > 0)); then
|
||||||
@@ -399,20 +488,19 @@ function timer_stop
|
|||||||
else
|
else
|
||||||
timer_show=${us}us
|
timer_show=${us}us
|
||||||
fi
|
fi
|
||||||
unset timer_start
|
unset _timer_start_us
|
||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Function triggered internally by bash : defining prompt
|
# Prompt segments. Each one puts its text in _PROMPT_SEG (empty when there is
|
||||||
# Usage: set_prompt
|
# nothing to show), without a command substitution (no subshell per segment).
|
||||||
# This function is called by bash before displaying the prompt. It sets the
|
# They are defined once, at load time, and not inside set_prompt: a function
|
||||||
# PS1 variable to a custom prompt that includes the exit status of the last
|
# definition resets $?, and set_prompt must read the exit status of the user's
|
||||||
# command, the elapsed time of the last command, and the current user and host.
|
# last command before anything else runs.
|
||||||
set_prompt()
|
|
||||||
|
_prompt_seg_git()
|
||||||
{
|
{
|
||||||
local _prompt_git_segment
|
_PROMPT_SEG=""
|
||||||
_prompt_git_segment()
|
|
||||||
{
|
|
||||||
# Fast path: skip git lookup when feature is disabled.
|
# Fast path: skip git lookup when feature is disabled.
|
||||||
[[ "${PROMPT_SHOW_GIT:-1}" == "0" ]] && return 0
|
[[ "${PROMPT_SHOW_GIT:-1}" == "0" ]] && return 0
|
||||||
|
|
||||||
@@ -421,77 +509,61 @@ set_prompt()
|
|||||||
branch=$(git rev-parse --short HEAD 2>/dev/null) || return 0
|
branch=$(git rev-parse --short HEAD 2>/dev/null) || return 0
|
||||||
|
|
||||||
local dirty="" sync="" timed_out=0
|
local dirty="" sync="" timed_out=0
|
||||||
local _git_timeout="${PROMPT_GIT_TIMEOUT:-2}"
|
|
||||||
|
|
||||||
|
if [[ "${PROMPT_SHOW_GIT_STATUS:-1}" != "0" ]]; then
|
||||||
# Build a timeout wrapper if the 'timeout' command is available;
|
# Build a timeout wrapper if the 'timeout' command is available;
|
||||||
# fall back to direct execution on systems that lack it.
|
# fall back to direct execution on systems that lack it.
|
||||||
local -a _tw=()
|
local -a _tw=()
|
||||||
command -v timeout >/dev/null 2>&1 && _tw=(timeout "$_git_timeout")
|
command -v timeout >/dev/null 2>&1 && _tw=(timeout "${PROMPT_GIT_TIMEOUT:-2}")
|
||||||
|
|
||||||
if [[ "${PROMPT_SHOW_GIT_STATUS:-1}" != "0" ]]; then
|
# One call for everything: --branch gives the "# branch.ab +A -B" line
|
||||||
local _ec
|
# (only when an upstream exists) and each changed tracked file gives a
|
||||||
|
# line starting with 1, 2 or u. Untracked files are not counted.
|
||||||
# Dirty check — working tree
|
# GIT_OPTIONAL_LOCKS=0 keeps git from taking the index lock to refresh
|
||||||
"${_tw[@]}" git diff --no-ext-diff --quiet --ignore-submodules -- 2>/dev/null
|
# it, which would make a concurrent "git commit" fail.
|
||||||
_ec=$?
|
local out ec
|
||||||
if [[ $_ec -eq 124 ]]; then
|
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
|
timed_out=1
|
||||||
elif [[ $_ec -ne 0 ]]; then
|
|
||||||
dirty="*"
|
|
||||||
else
|
else
|
||||||
# Dirty check — index
|
[[ $'\n'"$out" == *$'\n'[12u]\ * ]] && dirty="*"
|
||||||
"${_tw[@]}" git diff --cached --no-ext-diff --quiet --ignore-submodules -- 2>/dev/null
|
if [[ "$out" =~ \#\ branch\.ab\ \+([0-9]+)\ -([0-9]+) ]]; then
|
||||||
_ec=$?
|
if [[ "${BASH_REMATCH[1]}" -gt 0 || "${BASH_REMATCH[2]}" -gt 0 ]]; then
|
||||||
if [[ $_ec -eq 124 ]]; then
|
sync=" +${BASH_REMATCH[1]}/-${BASH_REMATCH[2]}"
|
||||||
timed_out=1
|
|
||||||
elif [[ $_ec -ne 0 ]]; then
|
|
||||||
dirty="*"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $timed_out -eq 0 ]]; then
|
|
||||||
local counts ahead behind
|
|
||||||
counts=$("${_tw[@]}" git rev-list --left-right --count "@{upstream}...HEAD" 2>/dev/null)
|
|
||||||
_ec=$?
|
|
||||||
if [[ $_ec -eq 124 ]]; then
|
|
||||||
timed_out=1
|
|
||||||
elif [[ "$counts" =~ ^([0-9]+)[[:space:]]+([0-9]+)$ ]]; then
|
|
||||||
behind="${BASH_REMATCH[1]}"
|
|
||||||
ahead="${BASH_REMATCH[2]}"
|
|
||||||
if [[ "$ahead" -gt 0 || "$behind" -gt 0 ]]; then
|
|
||||||
sync=" +${ahead}/-${behind}"
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $timed_out -eq 1 ]]; then
|
if [[ $timed_out -eq 1 ]]; then
|
||||||
printf "%s" "git:${branch}?"
|
_PROMPT_SEG="git:${branch}?"
|
||||||
else
|
else
|
||||||
printf "%s" "git:${branch}${dirty}${sync}"
|
_PROMPT_SEG="git:${branch}${dirty}${sync}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
local _prompt_conda_env
|
_prompt_seg_conda()
|
||||||
_prompt_conda_env()
|
{
|
||||||
{
|
_PROMPT_SEG=""
|
||||||
[[ "${PROMPT_SHOW_CONDA:-1}" == "0" ]] && return 0
|
[[ "${PROMPT_SHOW_CONDA:-1}" == "0" ]] && return 0
|
||||||
[[ -z "${CONDA_DEFAULT_ENV:-}" ]] && return 0
|
[[ -z "${CONDA_DEFAULT_ENV:-}" ]] && return 0
|
||||||
printf "%s" "conda:${CONDA_DEFAULT_ENV}"
|
_PROMPT_SEG="conda:${CONDA_DEFAULT_ENV}"
|
||||||
}
|
}
|
||||||
|
|
||||||
local _prompt_venv_env
|
_prompt_seg_venv()
|
||||||
_prompt_venv_env()
|
{
|
||||||
{
|
_PROMPT_SEG=""
|
||||||
[[ "${PROMPT_SHOW_VENV:-1}" == "0" ]] && return 0
|
[[ "${PROMPT_SHOW_VENV:-1}" == "0" ]] && return 0
|
||||||
[[ -n "${CONDA_DEFAULT_ENV:-}" ]] && return 0
|
[[ -n "${CONDA_DEFAULT_ENV:-}" ]] && return 0
|
||||||
[[ -z "${VIRTUAL_ENV:-}" ]] && return 0
|
[[ -z "${VIRTUAL_ENV:-}" ]] && return 0
|
||||||
printf "%s" "venv:${VIRTUAL_ENV##*/}"
|
_PROMPT_SEG="venv:${VIRTUAL_ENV##*/}"
|
||||||
}
|
}
|
||||||
|
|
||||||
local _prompt_session_markers
|
_prompt_seg_session()
|
||||||
_prompt_session_markers()
|
{
|
||||||
{
|
_PROMPT_SEG=""
|
||||||
[[ "${PROMPT_SHOW_SESSION:-1}" == "0" ]] && return 0
|
[[ "${PROMPT_SHOW_SESSION:-1}" == "0" ]] && return 0
|
||||||
|
|
||||||
local -a tags=()
|
local -a tags=()
|
||||||
@@ -504,13 +576,41 @@ set_prompt()
|
|||||||
for ((i=1; i<${#tags[@]}; ++i)); do
|
for ((i=1; i<${#tags[@]}; ++i)); do
|
||||||
out+="+${tags[i]}"
|
out+="+${tags[i]}"
|
||||||
done
|
done
|
||||||
printf "%s" "$out"
|
_PROMPT_SEG="$out"
|
||||||
}
|
}
|
||||||
|
|
||||||
local Last_Command=$? # Must come first!
|
# 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
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Function triggered internally by bash : defining prompt
|
||||||
|
# Usage: set_prompt
|
||||||
|
# This function is called by bash before displaying the prompt. It sets the
|
||||||
|
# PS1 variable to a custom prompt that includes the exit status of the last
|
||||||
|
# command, the elapsed time of the last command, and the current user and host.
|
||||||
|
set_prompt()
|
||||||
|
{
|
||||||
|
local Last_Command=$? # Must come first: nothing may run before this line
|
||||||
local FancyX='\342\234\227'
|
local FancyX='\342\234\227'
|
||||||
local Checkmark='\342\234\223'
|
local Checkmark='\342\234\223'
|
||||||
|
|
||||||
|
# The context segment is not copied into PS1. Bash expands PS1 when
|
||||||
|
# displaying it, including $(...) and `...`: a git branch (or conda
|
||||||
|
# environment) named 'x$(command)' would be executed. PS1 only contains the
|
||||||
|
# reference ${_PROMPT_CTX}, whose value is inserted as plain text, never
|
||||||
|
# re-scanned. This needs promptvars (the default).
|
||||||
|
shopt -q promptvars || shopt -s promptvars
|
||||||
|
|
||||||
# Resolve theme/config colours with hardcoded fallbacks
|
# Resolve theme/config colours with hardcoded fallbacks
|
||||||
local _time_fg="${PROMPT_COLOR_TIME_FG:-$Blue}"
|
local _time_fg="${PROMPT_COLOR_TIME_FG:-$Blue}"
|
||||||
local _time_bg="${PROMPT_COLOR_TIME_BG:-$On_White}"
|
local _time_bg="${PROMPT_COLOR_TIME_BG:-$On_White}"
|
||||||
@@ -533,20 +633,18 @@ set_prompt()
|
|||||||
|
|
||||||
# Add exit status of the last command.
|
# Add exit status of the last command.
|
||||||
# If it was successful, print a green check mark. Otherwise, print a red X.
|
# If it was successful, print a green check mark. Otherwise, print a red X.
|
||||||
|
timer_stop
|
||||||
if [[ $Last_Command == 0 ]]; then
|
if [[ $Last_Command == 0 ]]; then
|
||||||
PS1+="\[${_ok_fg}${_bar_bg}\] [ $Last_Command "
|
PS1+="\[${_ok_fg}${_bar_bg}\] [ $Last_Command "
|
||||||
PS1+="\[${_ok_mark}${_bar_bg}\]${Checkmark} "
|
PS1+="\[${_ok_mark}${_bar_bg}\]${Checkmark} "
|
||||||
# Add the elapsed time, then close the status section and return to bar bg.
|
# Add the elapsed time, then close the status section and return to bar bg.
|
||||||
timer_stop
|
|
||||||
PS1+="($timer_show)\[${_ok_fg}${_bar_bg}\] ] "
|
PS1+="($timer_show)\[${_ok_fg}${_bar_bg}\] ] "
|
||||||
else
|
else
|
||||||
PS1+="\[${_err_fg}${_err_bg}\] [ $Last_Command "
|
PS1+="\[${_err_fg}${_err_bg}\] [ $Last_Command "
|
||||||
PS1+="\[${_err_mark}${_err_bg}\]${FancyX} "
|
PS1+="\[${_err_mark}${_err_bg}\]${FancyX} "
|
||||||
timer_stop
|
|
||||||
PS1+="($timer_show)\[${_err_fg}${_err_bg}\] ] "
|
PS1+="($timer_show)\[${_err_fg}${_err_bg}\] ] "
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# If root, print the host in root colour. Otherwise use user colour.
|
# If root, print the host in root colour. Otherwise use user colour.
|
||||||
if [[ $EUID -eq 0 ]]; then
|
if [[ $EUID -eq 0 ]]; then
|
||||||
PS1+="\[${_root_fg}${_bar_bg}\] \\u\[${_user_fg}${_bar_bg}\]@\\h"
|
PS1+="\[${_root_fg}${_bar_bg}\] \\u\[${_user_fg}${_bar_bg}\]@\\h"
|
||||||
@@ -555,26 +653,14 @@ set_prompt()
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Optional context segment appended at the end of the top bar.
|
# Optional context segment appended at the end of the top bar.
|
||||||
local _git_seg _conda_env _venv_env _session_tags _ctx=""
|
_PROMPT_CTX=""
|
||||||
_git_seg="$(_prompt_git_segment)"
|
_prompt_seg_git; _prompt_ctx_add
|
||||||
_conda_env="$(_prompt_conda_env)"
|
_prompt_seg_conda; _prompt_ctx_add
|
||||||
_venv_env="$(_prompt_venv_env)"
|
_prompt_seg_venv; _prompt_ctx_add
|
||||||
_session_tags="$(_prompt_session_markers)"
|
_prompt_seg_session; _prompt_ctx_add
|
||||||
|
if [[ -n "$_PROMPT_CTX" ]]; then
|
||||||
local _ctx_disp
|
# Single quotes: the reference must reach PS1 literally (see above)
|
||||||
_ctx_disp()
|
PS1+="\[${_ctx_fg}${_bar_bg}\] [ "'${_PROMPT_CTX}'" ]"
|
||||||
{
|
|
||||||
[[ -n "$1" ]] && {
|
|
||||||
[[ -n "$_ctx" ]] && _ctx+=" | $1" || _ctx="$1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ctx_disp "$_git_seg"
|
|
||||||
_ctx_disp "$_conda_env"
|
|
||||||
_ctx_disp "$_venv_env"
|
|
||||||
_ctx_disp "$_session_tags"
|
|
||||||
if [[ -n "$_ctx" ]]; then
|
|
||||||
PS1+="\[${_ctx_fg}${_bar_bg}\] [ ${_ctx} ]"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PS1+="\[\e[K\e[u\]\[$RESETCOL\]\n"
|
PS1+="\[\e[K\e[u\]\[$RESETCOL\]\n"
|
||||||
@@ -591,15 +677,17 @@ set_prompt()
|
|||||||
# 2. Theme file (PROMPT_THEME key from [prompt] section)
|
# 2. Theme file (PROMPT_THEME key from [prompt] section)
|
||||||
# 3. Individual PROMPT_COLOR_* overrides in [prompt] section
|
# 3. Individual PROMPT_COLOR_* overrides in [prompt] section
|
||||||
#
|
#
|
||||||
|
# load_conf "prompt" (top of this file) has exported every key of the section,
|
||||||
|
# the theme file is loaded over them, and _prompt_apply_overrides then puts the
|
||||||
|
# PROMPT_COLOR_* keys of the section back on top (resolving $ColorName values).
|
||||||
# CONF_prompt is already populated by parse_conf (run in profile.sh before
|
# CONF_prompt is already populated by parse_conf (run in profile.sh before
|
||||||
# modules are sourced). We extract PROMPT_THEME and PROMPT_THEME_DIR from the
|
# modules are sourced), which is where PROMPT_THEME and PROMPT_THEME_DIR are
|
||||||
# raw associative array now so load_theme can run before load_conf "prompt"
|
# read from.
|
||||||
# exports remaining keys. That way any PROMPT_COLOR_* value set explicitly in
|
|
||||||
# [prompt] wins over the same variable set by the theme file.
|
|
||||||
_pt_theme="${CONF_prompt[PROMPT_THEME]:-}"
|
_pt_theme="${CONF_prompt[PROMPT_THEME]:-}"
|
||||||
_pt_dir="${CONF_prompt[PROMPT_THEME_DIR]:-}"
|
_pt_dir="${CONF_prompt[PROMPT_THEME_DIR]:-}"
|
||||||
[[ -n "$_pt_theme" ]] && load_theme "$_pt_theme" ${_pt_dir:+"$_pt_dir"}
|
[[ -n "$_pt_theme" ]] && load_theme "$_pt_theme" ${_pt_dir:+"$_pt_dir"}
|
||||||
unset _pt_theme _pt_dir
|
unset _pt_theme _pt_dir
|
||||||
|
_prompt_apply_overrides
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+13
-1
@@ -278,11 +278,23 @@ parse_conf()
|
|||||||
value="${value//\`/}"
|
value="${value//\`/}"
|
||||||
value="${value//\$\(/}"
|
value="${value//\$\(/}"
|
||||||
|
|
||||||
# Correctly interpretet internal variables (e.g. $HOME)
|
# Correctly interpretet internal variables (e.g. $HOME). In the
|
||||||
|
# [prompt] section only the variables that exist are substituted:
|
||||||
|
# envsubst would otherwise replace an unknown one by nothing,
|
||||||
|
# wiping out the $Blue-style colour references that are resolved
|
||||||
|
# later, when the colour variables exist (see prompt.sh).
|
||||||
if [[ "$value" == *\$* ]]; then
|
if [[ "$value" == *\$* ]]; then
|
||||||
if command -v envsubst >/dev/null 2>&1; then
|
if command -v envsubst >/dev/null 2>&1; then
|
||||||
|
if [[ "$current_section" == "prompt" ]]; then
|
||||||
|
local _envnames="" _envname
|
||||||
|
for _envname in $(compgen -e); do
|
||||||
|
[[ "$_envname" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] && _envnames+="\${${_envname}}"
|
||||||
|
done
|
||||||
|
value=$(envsubst "$_envnames" <<< "$value")
|
||||||
|
else
|
||||||
value=$(envsubst <<< "$value")
|
value=$(envsubst <<< "$value")
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
# If envsubst is unavailable, $VAR references are left as-is.
|
# If envsubst is unavailable, $VAR references are left as-is.
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user