From d22b24e54c3dc2f7cbb80ab0b99e8ab597c81dc7 Mon Sep 17 00:00:00 2001 From: fatalerrors Date: Wed, 20 May 2026 14:14:06 +0200 Subject: [PATCH] prompt now display contextual infos --- README.md | 24 +++++- doc/profile.conf.example | 18 +++++ doc/todo.md | 13 ++-- profile.d/prompt.sh | 100 +++++++++++++++++++++++++ profile.d/themes/abyss.theme | 1 + profile.d/themes/adwaita.theme | 1 + profile.d/themes/dark.theme | 1 + profile.d/themes/default.theme | 1 + profile.d/themes/light.theme | 1 + profile.d/themes/monochrome.theme | 1 + profile.d/themes/monokai.theme | 1 + profile.d/themes/plasma.theme | 1 + profile.d/themes/solarized-light.theme | 1 + profile.d/themes/solarized.theme | 1 + 14 files changed, 159 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1af9746..ff12d5d 100644 --- a/README.md +++ b/README.md @@ -308,7 +308,7 @@ PROMPT_COLOR_USER_FG = $ICyan PROMPT_COLOR_DIR_FG = $IYellow ``` -The eleven available `PROMPT_COLOR_*` keys are: +The twelve available `PROMPT_COLOR_*` keys are: | Key | Role | |---|---| @@ -319,6 +319,28 @@ The eleven available `PROMPT_COLOR_*` keys are: | `PROMPT_COLOR_ROOT_FG` | Username colour when running as root | | `PROMPT_COLOR_USER_FG` | Username@host colour for normal users | | `PROMPT_COLOR_DIR_FG` | Working directory colour | +| `PROMPT_COLOR_CTX_FG` | Git/Conda context segment colour at end of top bar | + +**Top-bar context segment (Git / Conda):** + +```ini +[prompt] +PROMPT_SHOW_GIT = 1 +PROMPT_SHOW_GIT_STATUS = 1 +PROMPT_SHOW_CONDA = 1 +PROMPT_SHOW_VENV = 1 +PROMPT_SHOW_SESSION = 1 +``` + +When enabled, the top prompt bar appends: + +- `git:` when inside a Git repository +- `git:*` when local changes are present +- `git: +N/-M` when ahead/behind upstream +- `conda:` when a Conda environment is active +- `venv:` when a Python virtualenv is active (and Conda is not) +- `ssh`, `tmux`, `screen` markers when the session runs in those contexts +- both, separated by `|`, when both are available **Writing a custom theme file:** diff --git a/doc/profile.conf.example b/doc/profile.conf.example index 9b4303f..f813ac7 100755 --- a/doc/profile.conf.example +++ b/doc/profile.conf.example @@ -171,6 +171,24 @@ TERM=xterm-256color # # Working directory #PROMPT_COLOR_DIR_FG=$ICyan +# +# Context segment (Git branch / Conda environment) on the top bar +#PROMPT_COLOR_CTX_FG=$BIYellow +# +# Show Git branch at the end of the top bar when inside a repository. +#PROMPT_SHOW_GIT=1 +# +# Include Git dirty marker and upstream drift (+ahead/-behind) in the context. +#PROMPT_SHOW_GIT_STATUS=1 +# +# Show Conda environment name at the end of the top bar when active. +#PROMPT_SHOW_CONDA=1 +# +# Show Python venv name when active (ignored if Conda is active). +#PROMPT_SHOW_VENV=1 +# +# Show session markers (ssh, tmux, screen) when applicable. +#PROMPT_SHOW_SESSION=1 # ============================================================================== [pwd] diff --git a/doc/todo.md b/doc/todo.md index 1e88d27..a876302 100755 --- a/doc/todo.md +++ b/doc/todo.md @@ -20,11 +20,14 @@ version-bump. ## Prompt & theming -- [ ] **Git branch in prompt** — show the current branch name (and dirty - indicator) in the PS1 bar when inside a Git repository. Should be - gated behind a `[prompt]` config key so it can be disabled. **[medium]** -- [ ] **Virtual-env / conda indicator** — detect `$VIRTUAL_ENV` / `$CONDA_DEFAULT_ENV` - and display the name in the prompt bar. **[easy]** +- [x] **Git branch in prompt** — show the current branch name (with dirty and + upstream drift indicators) in the PS1 bar when inside a Git repository, + gated by `[prompt]` config keys. **[medium]** +- [x] **Virtual-env / conda indicator** — detect `$VIRTUAL_ENV` / `$CONDA_DEFAULT_ENV` + and display the active environment in the prompt bar. **[easy]** +- [x] **Session context markers** — display lightweight session markers + (`ssh`, `tmux`, `screen`) at the end of the prompt bar, gated by + `[prompt]` config keys. **[easy]** - [ ] **True-colour terminal auto-detection** — query `$COLORTERM` and `$TERM` at load time; automatically fall back from a 24-bit theme to its 16-colour equivalent when the terminal does not support true colour. **[medium]** diff --git a/profile.d/prompt.sh b/profile.d/prompt.sh index fb39eba..b9f5d05 100644 --- a/profile.d/prompt.sh +++ b/profile.d/prompt.sh @@ -78,6 +78,7 @@ load_theme() [PROMPT_COLOR_ERR_BG]=1 [PROMPT_COLOR_ERR_FG]=1 [PROMPT_COLOR_ERR_MARK]=1 [PROMPT_COLOR_ROOT_FG]=1 [PROMPT_COLOR_USER_FG]=1 [PROMPT_COLOR_DIR_FG]=1 + [PROMPT_COLOR_CTX_FG]=1 ) # ---- Colour variable names exported by disp.sh -------------------------- @@ -285,6 +286,68 @@ function timer_stop # command, the elapsed time of the last command, and the current user and host. set_prompt() { + _prompt_git_segment() + { + # 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="" + if [[ "${PROMPT_SHOW_GIT_STATUS:-1}" != "0" ]]; then + if ! git diff --no-ext-diff --quiet --ignore-submodules -- 2>/dev/null || \ + ! git diff --cached --no-ext-diff --quiet --ignore-submodules -- 2>/dev/null; then + dirty="*" + fi + + local counts ahead behind + counts=$(git rev-list --left-right --count @{upstream}...HEAD 2>/dev/null) || counts="" + if [[ "$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 + + printf "%s" "git:${branch}${dirty}${sync}" + } + + _prompt_conda_env() + { + [[ "${PROMPT_SHOW_CONDA:-1}" == "0" ]] && return 0 + [[ -z "${CONDA_DEFAULT_ENV:-}" ]] && return 0 + printf "%s" "conda:${CONDA_DEFAULT_ENV}" + } + + _prompt_venv_env() + { + [[ "${PROMPT_SHOW_VENV:-1}" == "0" ]] && return 0 + [[ -n "${CONDA_DEFAULT_ENV:-}" ]] && return 0 + [[ -z "${VIRTUAL_ENV:-}" ]] && return 0 + printf "%s" "venv:${VIRTUAL_ENV##*/}" + } + + _prompt_session_markers() + { + [[ "${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 + printf "%s" "$out" + } + local Last_Command=$? # Must come first! local FancyX='\342\234\227' local Checkmark='\342\234\223' @@ -301,6 +364,7 @@ set_prompt() local _root_fg="${PROMPT_COLOR_ROOT_FG:-$Red}" local _user_fg="${PROMPT_COLOR_USER_FG:-$BGreen}" local _dir_fg="${PROMPT_COLOR_DIR_FG:-$ICyan}" + local _ctx_fg="${PROMPT_COLOR_CTX_FG:-$BIYellow}" # Begin with time (cursor-save is non-printing; all ANSI sequences wrapped # in \[...\] so bash does not count them toward the visible line width). @@ -330,6 +394,42 @@ set_prompt() else PS1+="\[${_user_fg}${_bar_bg}\] \\u@\\h" fi + + # Optional context segment appended at the end of the top bar. + local _git_seg _conda_env _venv_env _session_tags _ctx="" + _git_seg="$(_prompt_git_segment)" + _conda_env="$(_prompt_conda_env)" + _venv_env="$(_prompt_venv_env)" + _session_tags="$(_prompt_session_markers)" + + if [[ -n "$_git_seg" ]]; then + _ctx="$_git_seg" + fi + if [[ -n "$_conda_env" ]]; then + if [[ -n "$_ctx" ]]; then + _ctx+=" | ${_conda_env}" + else + _ctx="${_conda_env}" + fi + fi + if [[ -n "$_venv_env" ]]; then + if [[ -n "$_ctx" ]]; then + _ctx+=" | ${_venv_env}" + else + _ctx="${_venv_env}" + fi + fi + if [[ -n "$_session_tags" ]]; then + if [[ -n "$_ctx" ]]; then + _ctx+=" | ${_session_tags}" + else + _ctx="${_session_tags}" + fi + fi + if [[ -n "$_ctx" ]]; then + PS1+="\[${_ctx_fg}${_bar_bg}\] [ ${_ctx} ]" + fi + PS1+="\[\e[K\e[u\]\[$RESETCOL\]\n" # Print the working directory and prompt marker, then reset colour. PS1+="\[${_dir_fg}\]\\w \\\$\[$RESETCOL\] " diff --git a/profile.d/themes/abyss.theme b/profile.d/themes/abyss.theme index b55e2a5..ce41d5e 100644 --- a/profile.d/themes/abyss.theme +++ b/profile.d/themes/abyss.theme @@ -40,3 +40,4 @@ PROMPT_COLOR_ERR_MARK="$IYellow" # golden X PROMPT_COLOR_ROOT_FG="$IRed" # red for root PROMPT_COLOR_USER_FG="$IBlue" # electric blue for user PROMPT_COLOR_DIR_FG="$ICyan" # teal path +PROMPT_COLOR_CTX_FG="$IYellow" # context segment (git/conda) diff --git a/profile.d/themes/adwaita.theme b/profile.d/themes/adwaita.theme index a61c358..642082d 100644 --- a/profile.d/themes/adwaita.theme +++ b/profile.d/themes/adwaita.theme @@ -40,3 +40,4 @@ PROMPT_COLOR_ERR_MARK="$Yellow" # yellow X (warning intent) PROMPT_COLOR_ROOT_FG="$Red" # Adwaita red for root PROMPT_COLOR_USER_FG="$BBlue" # darker bold blue — readable on blue bar PROMPT_COLOR_DIR_FG="$IGreen" # Adwaita green for path +PROMPT_COLOR_CTX_FG="$BIWhite" # context segment (git/conda) diff --git a/profile.d/themes/dark.theme b/profile.d/themes/dark.theme index 0b291b2..50c7de9 100644 --- a/profile.d/themes/dark.theme +++ b/profile.d/themes/dark.theme @@ -30,3 +30,4 @@ PROMPT_COLOR_ERR_MARK="$BIYellow" # X mark colour on failure PROMPT_COLOR_ROOT_FG="$BIRed" # Username colour when root PROMPT_COLOR_USER_FG="$ICyan" # Username@host colour for normal users PROMPT_COLOR_DIR_FG="$IPurple" # Working directory colour +PROMPT_COLOR_CTX_FG="$BIYellow" # Context segment (git/conda) diff --git a/profile.d/themes/default.theme b/profile.d/themes/default.theme index 798c300..d61b4bd 100644 --- a/profile.d/themes/default.theme +++ b/profile.d/themes/default.theme @@ -30,3 +30,4 @@ PROMPT_COLOR_ERR_MARK="$BYellow" # X mark colour on failure PROMPT_COLOR_ROOT_FG="$Red" # Username colour when root PROMPT_COLOR_USER_FG="$Green" # Username@host colour for normal users PROMPT_COLOR_DIR_FG="$ICyan" # Working directory colour +PROMPT_COLOR_CTX_FG="$BIYellow" # Context segment (git/conda) diff --git a/profile.d/themes/light.theme b/profile.d/themes/light.theme index e14b379..ebf098c 100644 --- a/profile.d/themes/light.theme +++ b/profile.d/themes/light.theme @@ -33,3 +33,4 @@ PROMPT_COLOR_ERR_MARK="$BYellow" # X mark on failure (BIYellow → BYellow, l PROMPT_COLOR_ROOT_FG="$Red" # Username when root (BIRed → Red) PROMPT_COLOR_USER_FG="$Blue" # Username@host normal user (ICyan → Blue) PROMPT_COLOR_DIR_FG="$Purple" # Working directory (IPurple → Purple) +PROMPT_COLOR_CTX_FG="$BBlack" # Context segment (git/conda) diff --git a/profile.d/themes/monochrome.theme b/profile.d/themes/monochrome.theme index f36d2d4..ab7ec11 100644 --- a/profile.d/themes/monochrome.theme +++ b/profile.d/themes/monochrome.theme @@ -62,3 +62,4 @@ PROMPT_COLOR_ERR_MARK="$BBlack" # bold black X PROMPT_COLOR_ROOT_FG="$BIWhite" # bold bright white for root warning PROMPT_COLOR_USER_FG="$IWhite" # bright white for normal user PROMPT_COLOR_DIR_FG="$White" # standard white for path +PROMPT_COLOR_CTX_FG="$BIWhite" # context segment (git/conda) diff --git a/profile.d/themes/monokai.theme b/profile.d/themes/monokai.theme index 7719bbf..cdfceb8 100644 --- a/profile.d/themes/monokai.theme +++ b/profile.d/themes/monokai.theme @@ -43,3 +43,4 @@ PROMPT_COLOR_ERR_MARK="$IRed" # hot pink X PROMPT_COLOR_ROOT_FG="$IRed" # hot pink for root PROMPT_COLOR_USER_FG="$IYellow" # orange-yellow for user PROMPT_COLOR_DIR_FG="$ICyan" # electric cyan for path +PROMPT_COLOR_CTX_FG="$IYellow" # context segment (git/conda) diff --git a/profile.d/themes/plasma.theme b/profile.d/themes/plasma.theme index 773f48f..b7b9bf7 100644 --- a/profile.d/themes/plasma.theme +++ b/profile.d/themes/plasma.theme @@ -40,3 +40,4 @@ PROMPT_COLOR_ERR_MARK="$IYellow" # yellow X PROMPT_COLOR_ROOT_FG="$IRed" # red for root PROMPT_COLOR_USER_FG="$BIPurple" # bold vivid purple for user PROMPT_COLOR_DIR_FG="$ICyan" # electric cyan path +PROMPT_COLOR_CTX_FG="$IYellow" # context segment (git/conda) diff --git a/profile.d/themes/solarized-light.theme b/profile.d/themes/solarized-light.theme index 55edcc7..a6bdc07 100644 --- a/profile.d/themes/solarized-light.theme +++ b/profile.d/themes/solarized-light.theme @@ -125,3 +125,4 @@ PROMPT_COLOR_ERR_MARK="\e[38;2;253;246;227m" # Base3 — X mark (bright on red PROMPT_COLOR_ROOT_FG="\e[38;2;220;50;47m" # Red — root warning PROMPT_COLOR_USER_FG="\e[38;2;42;161;152m" # Cyan — normal user PROMPT_COLOR_DIR_FG="\e[38;2;38;139;210m" # Blue — working directory +PROMPT_COLOR_CTX_FG="\e[38;2;181;137;0m" # Yellow — context segment (git/conda) diff --git a/profile.d/themes/solarized.theme b/profile.d/themes/solarized.theme index 3af79d4..131409c 100644 --- a/profile.d/themes/solarized.theme +++ b/profile.d/themes/solarized.theme @@ -120,3 +120,4 @@ PROMPT_COLOR_ERR_MARK="\e[1;38;2;253;246;227m" # Base3 bold — bright warm mark PROMPT_COLOR_ROOT_FG="\e[38;2;220;50;47m" # Red — root warning PROMPT_COLOR_USER_FG="\e[38;2;42;161;152m" # Cyan — normal user PROMPT_COLOR_DIR_FG="\e[38;2;38;139;210m" # Blue — working directory +PROMPT_COLOR_CTX_FG="\e[38;2;181;137;0m" # Yellow — context segment (git/conda)