From 083cc2c8e8742bab8cce8c73a3e96f398e6b2da7 Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Thu, 7 Mar 2024 14:39:05 +0100 Subject: feat(async)!: implement async prompt API and apply to git prompt (#12257) BREAKING CHANGE: the `git_prompt_info` prompt function has been reworked by default to use the new async prompt feature. If you're experiencing issues see #12257. Co-authored-by: Carlo Sala --- lib/git.zsh | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'lib/git.zsh') diff --git a/lib/git.zsh b/lib/git.zsh index f049f73c2..6f4823458 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -9,14 +9,18 @@ function __git_prompt_git() { GIT_OPTIONAL_LOCKS=0 command git "$@" } -function git_prompt_info() { +function _omz_git_prompt_status() { # If we are on a folder not tracked by git, get out. # Otherwise, check for hide-info at global and local repository level if ! __git_prompt_git rev-parse --git-dir &> /dev/null \ - || [[ "$(__git_prompt_git config --get oh-my-zsh.hide-info 2>/dev/null)" == 1 ]]; then + || [[ "$(__git_prompt_git config --get oh-my-zsh.hide-info 2>/dev/null)" == 1 ]]; then return 0 fi + # Get either: + # - the current branch name + # - the tag name if we are on a tag + # - the short SHA of the current commit local ref ref=$(__git_prompt_git symbolic-ref --short HEAD 2> /dev/null) \ || ref=$(__git_prompt_git describe --tags --exact-match HEAD 2> /dev/null) \ @@ -33,6 +37,20 @@ function git_prompt_info() { echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref:gs/%/%%}${upstream:gs/%/%%}$(parse_git_dirty)${ZSH_THEME_GIT_PROMPT_SUFFIX}" } +# Enable async prompt by default unless the setting is at false / no +if zstyle -T ':omz:alpha:lib:git' async-prompt; then + function git_prompt_info() { + _omz_register_handler _omz_git_prompt_status + if [[ -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]" ]]; then + echo -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]" + fi + } +else + function git_prompt_info() { + _omz_git_prompt_status + } +fi + # Checks if working tree is dirty function parse_git_dirty() { local STATUS -- cgit v1.2.3-70-g09d2 From 32d4389aa6e896b27d9786d142a5c44163104056 Mon Sep 17 00:00:00 2001 From: Carlo Sala Date: Thu, 7 Mar 2024 17:17:27 +0100 Subject: fix(git): disable temporarely async prompt --- lib/git.zsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/git.zsh') diff --git a/lib/git.zsh b/lib/git.zsh index 6f4823458..8fe999095 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -38,7 +38,7 @@ function _omz_git_prompt_status() { } # Enable async prompt by default unless the setting is at false / no -if zstyle -T ':omz:alpha:lib:git' async-prompt; then +if zstyle -t ':omz:alpha:lib:git' async-prompt; then function git_prompt_info() { _omz_register_handler _omz_git_prompt_status if [[ -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]" ]]; then -- cgit v1.2.3-70-g09d2 From 06753e8146332aa787857fc5cc41caa2b5f753f0 Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Sat, 9 Mar 2024 18:22:35 +0100 Subject: fix(async): register the git prompt async handler correctly (#12267) This fix conditionally registers the git prompt async handler only if `git_prompt_info` is used anywhere in the prompt variables. This is done in the proper order, so that the async request is processed once the handler has been registered. This fix also passes the return value of the previous command to each of the async handlers, in case they are needed. --- lib/async_prompt.zsh | 12 +++++++++--- lib/git.zsh | 20 +++++++++++++++++++- 2 files changed, 28 insertions(+), 4 deletions(-) (limited to 'lib/git.zsh') diff --git a/lib/async_prompt.zsh b/lib/async_prompt.zsh index c6d03328b..384e49d33 100644 --- a/lib/async_prompt.zsh +++ b/lib/async_prompt.zsh @@ -5,8 +5,8 @@ zmodload zsh/system # For now, async prompt function handlers are set up like so: -# First, define the async function handler and add the function name -# to the _omz_async_functions array: +# First, define the async function handler and register the handler +# with _omz_register_handler: # # function _git_prompt_status_async { # # Do some expensive operation that outputs to stdout @@ -17,7 +17,7 @@ zmodload zsh/system # which will show the output of "$_OMZ_ASYNC_OUTPUT[handler_name]": # # function git_prompt_status { -# echo -n $_OMZ_ASYNC_OUTPUT[_git_prompt_status] +# echo -n $_OMZ_ASYNC_OUTPUT[_git_prompt_status_async] # } # # RPROMPT='$(git_prompt_status)' @@ -43,6 +43,7 @@ function _omz_register_handler { # Set up async handlers and callbacks function _omz_async_request { + local -i ret=$? typeset -gA _OMZ_ASYNC_FDS _OMZ_ASYNC_PIDS _OMZ_ASYNC_OUTPUT # executor runs a subshell for all async requests based on key @@ -83,6 +84,8 @@ function _omz_async_request { builtin echo ${sysparams[pid]} # Store handler name for callback builtin echo $handler + # Set exit code for the handler if used + (exit $ret) # Run the async function handler $handler ) @@ -138,3 +141,6 @@ function _omz_async_callback() { _OMZ_ASYNC_FDS[$handler]=-1 _OMZ_ASYNC_PIDS[$handler]=-1 } + +autoload -Uz add-zsh-hook +add-zsh-hook precmd _omz_async_request diff --git a/lib/git.zsh b/lib/git.zsh index 8fe999095..96df5589d 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -40,11 +40,29 @@ function _omz_git_prompt_status() { # Enable async prompt by default unless the setting is at false / no if zstyle -t ':omz:alpha:lib:git' async-prompt; then function git_prompt_info() { - _omz_register_handler _omz_git_prompt_status if [[ -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]" ]]; then echo -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]" fi } + + # Conditionally register the async handler, only if it's needed in $PROMPT + # or any of the other prompt variables + function _defer_async_git_register() { + # Check if git_prompt_info is used in a prompt variable + case "${PS1}:${PS2}:${PS3}:${PS4}:${RPS1}:${RPS2}:${RPS3}:${RPS4}" in + *(\$\(git_prompt_info\)|\`git_prompt_info\`)*) + _omz_register_handler _omz_git_prompt_status + return + ;; + esac + + add-zsh-hook -d precmd _defer_async_git_register + unset -f _defer_async_git_register + } + + # Register the async handler first. This needs to be done before + # the async request prompt is run + precmd_functions=(_defer_async_git_register $precmd_functions) else function git_prompt_info() { _omz_git_prompt_status -- cgit v1.2.3-70-g09d2 From ec1afe9dd683c36e6384db25fc1e95acbb0cbc7a Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Wed, 3 Apr 2024 19:55:46 +0200 Subject: feat(git)!: enable async git prompt (now for real) BREAKING CHANGE: the new async prompt feature will render prompt information asyncronously and degrade nicely when the calls take too long to finish, as the prompt will already be first drawn and interactive. This is enabled by default for the git prompt and themes that use it (`git_prompt_info`). If you find that it's not working for you, please open an issue if one is not already opened, and see https://github.com/ohmyzsh/ohmyzsh#disable-async-git-prompt for how to turn it off. --- README.md | 12 ++++++++++++ lib/git.zsh | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'lib/git.zsh') diff --git a/README.md b/README.md index b3561a833..2ba374335 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ To learn more, visit [ohmyz.sh](https://ohmyz.sh), follow [@ohmyzsh](https://twi - [Custom Plugins And Themes](#custom-plugins-and-themes) - [Enable GNU ls In macOS And freeBSD Systems](#enable-gnu-ls-in-macos-and-freebsd-systems) - [Skip Aliases](#skip-aliases) + - [Disable async git prompt](#disable-async-git-prompt) - [Getting Updates](#getting-updates) - [Updates Verbosity](#updates-verbosity) - [Manual Updates](#manual-updates) @@ -361,6 +362,17 @@ Instead, you can now use the following: zstyle ':omz:lib:directories' aliases no ``` +### Disable async git prompt + +Async prompt functions are an experimental feature (included on April 3, 2024) that allows Oh My Zsh to render prompt information +asyncronously. This can improve prompt rendering performance, but it might not work well with some setups. We hope that's not an +issue, but if you're seeing problems with this new feature, you can turn it of by setting the following in your .zshrc file, +before Oh My Zsh is sourced: + +```sh +zstyle ':omz:alpha:lib:git' async-prompt no +``` + #### Notice > This feature is currently in a testing phase and it may be subject to change in the future. diff --git a/lib/git.zsh b/lib/git.zsh index 96df5589d..4d6681c5b 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -38,7 +38,7 @@ function _omz_git_prompt_status() { } # Enable async prompt by default unless the setting is at false / no -if zstyle -t ':omz:alpha:lib:git' async-prompt; then +if zstyle -T ':omz:alpha:lib:git' async-prompt; then function git_prompt_info() { if [[ -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]" ]]; then echo -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]" -- cgit v1.2.3-70-g09d2 From 04007a0e5d0a458efff23da896cf70dc40df585d Mon Sep 17 00:00:00 2001 From: Loïc Yhuel Date: Wed, 3 Apr 2024 21:32:16 +0200 Subject: feat(git): implement async completion for `git_prompt_status` (#12319) This is important for themes using it, since it is usually a little slower than git_prompt_info. Also two small fixes : - the handler for git_prompt_info was incorrectly named _omz_git_prompt_status - _defer_async_git_register was kept in precmd, there is no need to call it on each prompt --- lib/git.zsh | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'lib/git.zsh') diff --git a/lib/git.zsh b/lib/git.zsh index 4d6681c5b..76b3778db 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -9,7 +9,7 @@ function __git_prompt_git() { GIT_OPTIONAL_LOCKS=0 command git "$@" } -function _omz_git_prompt_status() { +function _omz_git_prompt_info() { # If we are on a folder not tracked by git, get out. # Otherwise, check for hide-info at global and local repository level if ! __git_prompt_git rev-parse --git-dir &> /dev/null \ @@ -40,6 +40,12 @@ function _omz_git_prompt_status() { # Enable async prompt by default unless the setting is at false / no if zstyle -T ':omz:alpha:lib:git' async-prompt; then function git_prompt_info() { + if [[ -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]" ]]; then + echo -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]" + fi + } + + function git_prompt_status() { if [[ -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]" ]]; then echo -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]" fi @@ -51,8 +57,13 @@ if zstyle -T ':omz:alpha:lib:git' async-prompt; then # Check if git_prompt_info is used in a prompt variable case "${PS1}:${PS2}:${PS3}:${PS4}:${RPS1}:${RPS2}:${RPS3}:${RPS4}" in *(\$\(git_prompt_info\)|\`git_prompt_info\`)*) + _omz_register_handler _omz_git_prompt_info + ;; + esac + + case "${PS1}:${PS2}:${PS3}:${PS4}:${RPS1}:${RPS2}:${RPS3}:${RPS4}" in + *(\$\(git_prompt_status\)|\`git_prompt_status\`)*) _omz_register_handler _omz_git_prompt_status - return ;; esac @@ -65,6 +76,9 @@ if zstyle -T ':omz:alpha:lib:git' async-prompt; then precmd_functions=(_defer_async_git_register $precmd_functions) else function git_prompt_info() { + _omz_git_prompt_info + } + function git_prompt_status() { _omz_git_prompt_status } fi @@ -197,7 +211,7 @@ function git_prompt_long_sha() { SHA=$(__git_prompt_git rev-parse HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER" } -function git_prompt_status() { +function _omz_git_prompt_status() { [[ "$(__git_prompt_git config --get oh-my-zsh.hide-status 2>/dev/null)" = 1 ]] && return # Maps a git status prefix to an internal constant -- cgit v1.2.3-70-g09d2 From 114b58ed4e93faee352187779c7151f8580f24fe Mon Sep 17 00:00:00 2001 From: Carlo Sala Date: Thu, 4 Apr 2024 11:58:43 +0200 Subject: fix(git): disable locally `ksharrays` Fixes #12321 --- lib/git.zsh | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/git.zsh') diff --git a/lib/git.zsh b/lib/git.zsh index 76b3778db..23d11db2d 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -40,12 +40,14 @@ function _omz_git_prompt_info() { # Enable async prompt by default unless the setting is at false / no if zstyle -T ':omz:alpha:lib:git' async-prompt; then function git_prompt_info() { + setopt localoptions noksharrays if [[ -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]" ]]; then echo -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]" fi } function git_prompt_status() { + setopt localoptions noksharrays if [[ -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]" ]]; then echo -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]" fi -- cgit v1.2.3-70-g09d2 From 038931039030911852d456215d6f39385d5b7a6e Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Fri, 5 Apr 2024 07:38:36 +0200 Subject: fix(lib/git): fix detection of function use in prompt RPS1 and RPROMPT are not equivalent, though they have the same effect. Added both to detect if `git_prompt_*` is used. Fixes #12325 --- lib/git.zsh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/git.zsh') diff --git a/lib/git.zsh b/lib/git.zsh index 23d11db2d..c4265970b 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -57,13 +57,13 @@ if zstyle -T ':omz:alpha:lib:git' async-prompt; then # or any of the other prompt variables function _defer_async_git_register() { # Check if git_prompt_info is used in a prompt variable - case "${PS1}:${PS2}:${PS3}:${PS4}:${RPS1}:${RPS2}:${RPS3}:${RPS4}" in + case "${PS1}:${PS2}:${PS3}:${PS4}:${RPROMPT}:${RPS1}:${RPS2}:${RPS3}:${RPS4}" in *(\$\(git_prompt_info\)|\`git_prompt_info\`)*) _omz_register_handler _omz_git_prompt_info ;; esac - case "${PS1}:${PS2}:${PS3}:${PS4}:${RPS1}:${RPS2}:${RPS3}:${RPS4}" in + case "${PS1}:${PS2}:${PS3}:${PS4}:${RPROMPT}:${RPS1}:${RPS2}:${RPS3}:${RPS4}" in *(\$\(git_prompt_status\)|\`git_prompt_status\`)*) _omz_register_handler _omz_git_prompt_status ;; -- cgit v1.2.3-70-g09d2 From 1ed8d4b55530888bfa723e7dc6226a798260bdc8 Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Wed, 17 Apr 2024 20:21:18 +0200 Subject: fix(git): turn off async prompt by default on zsh < 5.0.6 (#12331) See https://github.com/ohmyzsh/ohmyzsh/issues/12331#issuecomment-2059460268 --- lib/git.zsh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib/git.zsh') diff --git a/lib/git.zsh b/lib/git.zsh index c4265970b..277c0b3e8 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -1,3 +1,5 @@ +autoload -Uz is-at-least + # The git prompt's git commands are read-only and should not interfere with # other processes. This environment variable is equivalent to running with `git # --no-optional-locks`, but falls back gracefully for older versions of git. @@ -37,8 +39,10 @@ function _omz_git_prompt_info() { echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref:gs/%/%%}${upstream:gs/%/%%}$(parse_git_dirty)${ZSH_THEME_GIT_PROMPT_SUFFIX}" } -# Enable async prompt by default unless the setting is at false / no -if zstyle -T ':omz:alpha:lib:git' async-prompt; then +# Use async version if setting is enabled, or undefined but zsh version is at least 5.0.6 +# https://github.com/ohmyzsh/ohmyzsh/issues/12331#issuecomment-2059460268 +if zstyle -t ':omz:alpha:lib:git' async-prompt \ + || { is-at-least 5.0.6 && zstyle -T ':omz:alpha:lib:git' async-prompt }; then function git_prompt_info() { setopt localoptions noksharrays if [[ -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]" ]]; then -- cgit v1.2.3-70-g09d2 From 0c80a063c3ad9513b83589d377c501a8d85d63a6 Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Fri, 19 Apr 2024 18:47:21 +0200 Subject: chore(async): reenable async prompt by default on zsh < 5.0.6 (#12358) Fixes #12331 --- lib/git.zsh | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'lib/git.zsh') diff --git a/lib/git.zsh b/lib/git.zsh index 277c0b3e8..b257d01a4 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -39,21 +39,17 @@ function _omz_git_prompt_info() { echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref:gs/%/%%}${upstream:gs/%/%%}$(parse_git_dirty)${ZSH_THEME_GIT_PROMPT_SUFFIX}" } -# Use async version if setting is enabled, or undefined but zsh version is at least 5.0.6 -# https://github.com/ohmyzsh/ohmyzsh/issues/12331#issuecomment-2059460268 -if zstyle -t ':omz:alpha:lib:git' async-prompt \ - || { is-at-least 5.0.6 && zstyle -T ':omz:alpha:lib:git' async-prompt }; then +# Use async version if setting is enabled or undefined +if zstyle -T ':omz:alpha:lib:git' async-prompt; then function git_prompt_info() { - setopt localoptions noksharrays - if [[ -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]" ]]; then - echo -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]" + if [[ -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]}" ]]; then + echo -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]}" fi } function git_prompt_status() { - setopt localoptions noksharrays - if [[ -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]" ]]; then - echo -n "$_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]" + if [[ -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]}" ]]; then + echo -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]}" fi } -- cgit v1.2.3-70-g09d2 From 59e8e028e179fc126d46254900946953072048e7 Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Wed, 12 Jun 2024 10:32:30 +0200 Subject: fix(lib/git): turn off async prompt for zsh < 5.0.6 We removed this mitigation in 0c80a063 because of an assumption that the issue had been fixed, but it looks like zsh < 5.0.6 has other issues (see #12360), so we need to disable it for real. Fixes #12360 --- lib/git.zsh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'lib/git.zsh') diff --git a/lib/git.zsh b/lib/git.zsh index b257d01a4..db6c9174c 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -39,8 +39,13 @@ function _omz_git_prompt_info() { echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref:gs/%/%%}${upstream:gs/%/%%}$(parse_git_dirty)${ZSH_THEME_GIT_PROMPT_SUFFIX}" } -# Use async version if setting is enabled or undefined -if zstyle -T ':omz:alpha:lib:git' async-prompt; then +# Use async version if setting is enabled, or unset but zsh version is at least 5.0.6. +# This avoids async prompt issues caused by previous zsh versions: +# - https://github.com/ohmyzsh/ohmyzsh/issues/12331 +# - https://github.com/ohmyzsh/ohmyzsh/issues/12360 +# TODO(2024-06-12): @mcornella remove workaround when CentOS 7 reaches EOL +if zstyle -t ':omz:alpha:lib:git' async-prompt \ + || { is-at-least 5.0.6 && zstyle -T ':omz:alpha:lib:git' async-prompt }; then function git_prompt_info() { if [[ -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]}" ]]; then echo -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]}" -- cgit v1.2.3-70-g09d2 From 33ac2ee30f92183565b30ef2ed847870d0b9b052 Mon Sep 17 00:00:00 2001 From: Saravana J Date: Sun, 15 Sep 2024 11:47:43 +0530 Subject: fix(git): update prefix map for modified files (#12674) --- lib/git.zsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/git.zsh') diff --git a/lib/git.zsh b/lib/git.zsh index db6c9174c..2ad5afe04 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -227,7 +227,7 @@ function _omz_git_prompt_status() { prefix_constant_map=( '\?\? ' 'UNTRACKED' 'A ' 'ADDED' - 'M ' 'ADDED' + 'M ' 'MODIFIED' 'MM ' 'MODIFIED' ' M ' 'MODIFIED' 'AM ' 'MODIFIED' -- cgit v1.2.3-70-g09d2 From 99e2c31484bba519925a65b442d0516fc6e01c94 Mon Sep 17 00:00:00 2001 From: Carlo Sala Date: Wed, 18 Sep 2024 21:05:45 +0200 Subject: feat(git): add `git_previous_branch` function Closes #12538 --- lib/git.zsh | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'lib/git.zsh') diff --git a/lib/git.zsh b/lib/git.zsh index 2ad5afe04..8237af751 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -162,6 +162,18 @@ function git_current_branch() { echo ${ref#refs/heads/} } +# Outputs the name of the previously checked out branch +# Usage example: git pull origin $(git_current_branch) +# rev-parse --symbolic-full-name @{-1} only prints if it is a branch +function git_previous_branch() { + local ref + ref=$(__git_prompt_git rev-parse --quiet --symbolic-full-name @{-1} 2> /dev/null) + local ret=$? + if [[ $ret != 0 ]] || [[ -z $ref ]]; then + return # no git repo or non-branch previous ref + fi + echo ${ref#refs/heads/} +} # Gets the number of commits ahead from remote function git_commits_ahead() { -- cgit v1.2.3-70-g09d2 From 367e9381dfae65e020cb5c439818e04ae1dd9423 Mon Sep 17 00:00:00 2001 From: Carlo Sala Date: Mon, 23 Sep 2024 17:32:44 +0200 Subject: chore(git): fix typo --- lib/git.zsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/git.zsh') diff --git a/lib/git.zsh b/lib/git.zsh index 8237af751..0efff3e07 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -163,7 +163,7 @@ function git_current_branch() { } # Outputs the name of the previously checked out branch -# Usage example: git pull origin $(git_current_branch) +# Usage example: git pull origin $(git_previous_branch) # rev-parse --symbolic-full-name @{-1} only prints if it is a branch function git_previous_branch() { local ref -- cgit v1.2.3-70-g09d2 From 2a109d30afe4ab164a946c307abc3d2a444a42ad Mon Sep 17 00:00:00 2001 From: Carlo Sala Date: Tue, 8 Oct 2024 20:26:23 +0200 Subject: feat(git): add escape hatch to enable async prompt --- README.md | 12 ++++++++++-- lib/git.zsh | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) (limited to 'lib/git.zsh') diff --git a/README.md b/README.md index 78db3a88f..1303292d2 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Twitter), and join us on [Discord](https://discord.gg/ohmyzsh). - [Custom Plugins And Themes](#custom-plugins-and-themes) - [Enable GNU ls In macOS And freeBSD Systems](#enable-gnu-ls-in-macos-and-freebsd-systems) - [Skip Aliases](#skip-aliases) - - [Disable async git prompt](#disable-async-git-prompt) + - [Async git prompt](#async-git-prompt) - [Getting Updates](#getting-updates) - [Updates Verbosity](#updates-verbosity) - [Manual Updates](#manual-updates) @@ -415,7 +415,7 @@ zstyle ':omz:lib:directories' aliases no > It is also not currently aware of "aliases" that are defined as functions. Example of such are `gccd`, > `ggf`, or `ggl` functions from the git plugin. -### Disable async git prompt +### Async git prompt Async prompt functions are an experimental feature (included on April 3, 2024) that allows Oh My Zsh to render prompt information asynchronously. This can improve prompt rendering performance, but it might not work well @@ -426,6 +426,14 @@ turn it off by setting the following in your .zshrc file, before Oh My Zsh is so zstyle ':omz:alpha:lib:git' async-prompt no ``` +If your problem is that the git prompt just stopped appearing, you can try to force it setting the following +configuration before `oh-my-zsh.sh` is sourced. If it still does not work, please open an issue with your +case. + +```sh +zstyle ':omz:alpha:lib:git' async-prompt force +``` + ## Getting Updates By default, you will be prompted to check for updates every 2 weeks. You can choose other update modes by diff --git a/lib/git.zsh b/lib/git.zsh index 0efff3e07..a1b4d1587 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -44,6 +44,7 @@ function _omz_git_prompt_info() { # - https://github.com/ohmyzsh/ohmyzsh/issues/12331 # - https://github.com/ohmyzsh/ohmyzsh/issues/12360 # TODO(2024-06-12): @mcornella remove workaround when CentOS 7 reaches EOL +local _style if zstyle -t ':omz:alpha:lib:git' async-prompt \ || { is-at-least 5.0.6 && zstyle -T ':omz:alpha:lib:git' async-prompt }; then function git_prompt_info() { @@ -81,6 +82,21 @@ if zstyle -t ':omz:alpha:lib:git' async-prompt \ # Register the async handler first. This needs to be done before # the async request prompt is run precmd_functions=(_defer_async_git_register $precmd_functions) +elif zstyle -s ':omz:alpha:lib:git' async-prompt _style && [[ $_style == "force" ]]; then + function git_prompt_info() { + if [[ -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]}" ]]; then + echo -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]}" + fi + } + + function git_prompt_status() { + if [[ -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]}" ]]; then + echo -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]}" + fi + } + + _omz_register_handler _omz_git_prompt_info + _omz_register_handler _omz_git_prompt_status else function git_prompt_info() { _omz_git_prompt_info -- cgit v1.2.3-70-g09d2 From 13c702964c0287059a75eaec98cd71de51f4f19c Mon Sep 17 00:00:00 2001 From: Ilia Burtsev Date: Sat, 24 May 2025 13:39:17 +0300 Subject: fix(async): ensure `git_prompt_status` can be registered (#13134) --- lib/git.zsh | 198 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 99 insertions(+), 99 deletions(-) (limited to 'lib/git.zsh') diff --git a/lib/git.zsh b/lib/git.zsh index a1b4d1587..f4d4229cb 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -39,6 +39,105 @@ function _omz_git_prompt_info() { echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref:gs/%/%%}${upstream:gs/%/%%}$(parse_git_dirty)${ZSH_THEME_GIT_PROMPT_SUFFIX}" } +function _omz_git_prompt_status() { + [[ "$(__git_prompt_git config --get oh-my-zsh.hide-status 2>/dev/null)" = 1 ]] && return + + # Maps a git status prefix to an internal constant + # This cannot use the prompt constants, as they may be empty + local -A prefix_constant_map + prefix_constant_map=( + '\?\? ' 'UNTRACKED' + 'A ' 'ADDED' + 'M ' 'MODIFIED' + 'MM ' 'MODIFIED' + ' M ' 'MODIFIED' + 'AM ' 'MODIFIED' + ' T ' 'MODIFIED' + 'R ' 'RENAMED' + ' D ' 'DELETED' + 'D ' 'DELETED' + 'UU ' 'UNMERGED' + 'ahead' 'AHEAD' + 'behind' 'BEHIND' + 'diverged' 'DIVERGED' + 'stashed' 'STASHED' + ) + + # Maps the internal constant to the prompt theme + local -A constant_prompt_map + constant_prompt_map=( + 'UNTRACKED' "$ZSH_THEME_GIT_PROMPT_UNTRACKED" + 'ADDED' "$ZSH_THEME_GIT_PROMPT_ADDED" + 'MODIFIED' "$ZSH_THEME_GIT_PROMPT_MODIFIED" + 'RENAMED' "$ZSH_THEME_GIT_PROMPT_RENAMED" + 'DELETED' "$ZSH_THEME_GIT_PROMPT_DELETED" + 'UNMERGED' "$ZSH_THEME_GIT_PROMPT_UNMERGED" + 'AHEAD' "$ZSH_THEME_GIT_PROMPT_AHEAD" + 'BEHIND' "$ZSH_THEME_GIT_PROMPT_BEHIND" + 'DIVERGED' "$ZSH_THEME_GIT_PROMPT_DIVERGED" + 'STASHED' "$ZSH_THEME_GIT_PROMPT_STASHED" + ) + + # The order that the prompt displays should be added to the prompt + local status_constants + status_constants=( + UNTRACKED ADDED MODIFIED RENAMED DELETED + STASHED UNMERGED AHEAD BEHIND DIVERGED + ) + + local status_text + status_text="$(__git_prompt_git status --porcelain -b 2> /dev/null)" + + # Don't continue on a catastrophic failure + if [[ $? -eq 128 ]]; then + return 1 + fi + + # A lookup table of each git status encountered + local -A statuses_seen + + if __git_prompt_git rev-parse --verify refs/stash &>/dev/null; then + statuses_seen[STASHED]=1 + fi + + local status_lines + status_lines=("${(@f)${status_text}}") + + # If the tracking line exists, get and parse it + if [[ "$status_lines[1]" =~ "^## [^ ]+ \[(.*)\]" ]]; then + local branch_statuses + branch_statuses=("${(@s/,/)match}") + for branch_status in $branch_statuses; do + if [[ ! $branch_status =~ "(behind|diverged|ahead) ([0-9]+)?" ]]; then + continue + fi + local last_parsed_status=$prefix_constant_map[$match[1]] + statuses_seen[$last_parsed_status]=$match[2] + done + fi + + # For each status prefix, do a regex comparison + for status_prefix in ${(k)prefix_constant_map}; do + local status_constant="${prefix_constant_map[$status_prefix]}" + local status_regex=$'(^|\n)'"$status_prefix" + + if [[ "$status_text" =~ $status_regex ]]; then + statuses_seen[$status_constant]=1 + fi + done + + # Display the seen statuses in the order specified + local status_prompt + for status_constant in $status_constants; do + if (( ${+statuses_seen[$status_constant]} )); then + local next_display=$constant_prompt_map[$status_constant] + status_prompt="$next_display$status_prompt" + fi + done + + echo $status_prompt +} + # Use async version if setting is enabled, or unset but zsh version is at least 5.0.6. # This avoids async prompt issues caused by previous zsh versions: # - https://github.com/ohmyzsh/ohmyzsh/issues/12331 @@ -246,105 +345,6 @@ function git_prompt_long_sha() { SHA=$(__git_prompt_git rev-parse HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER" } -function _omz_git_prompt_status() { - [[ "$(__git_prompt_git config --get oh-my-zsh.hide-status 2>/dev/null)" = 1 ]] && return - - # Maps a git status prefix to an internal constant - # This cannot use the prompt constants, as they may be empty - local -A prefix_constant_map - prefix_constant_map=( - '\?\? ' 'UNTRACKED' - 'A ' 'ADDED' - 'M ' 'MODIFIED' - 'MM ' 'MODIFIED' - ' M ' 'MODIFIED' - 'AM ' 'MODIFIED' - ' T ' 'MODIFIED' - 'R ' 'RENAMED' - ' D ' 'DELETED' - 'D ' 'DELETED' - 'UU ' 'UNMERGED' - 'ahead' 'AHEAD' - 'behind' 'BEHIND' - 'diverged' 'DIVERGED' - 'stashed' 'STASHED' - ) - - # Maps the internal constant to the prompt theme - local -A constant_prompt_map - constant_prompt_map=( - 'UNTRACKED' "$ZSH_THEME_GIT_PROMPT_UNTRACKED" - 'ADDED' "$ZSH_THEME_GIT_PROMPT_ADDED" - 'MODIFIED' "$ZSH_THEME_GIT_PROMPT_MODIFIED" - 'RENAMED' "$ZSH_THEME_GIT_PROMPT_RENAMED" - 'DELETED' "$ZSH_THEME_GIT_PROMPT_DELETED" - 'UNMERGED' "$ZSH_THEME_GIT_PROMPT_UNMERGED" - 'AHEAD' "$ZSH_THEME_GIT_PROMPT_AHEAD" - 'BEHIND' "$ZSH_THEME_GIT_PROMPT_BEHIND" - 'DIVERGED' "$ZSH_THEME_GIT_PROMPT_DIVERGED" - 'STASHED' "$ZSH_THEME_GIT_PROMPT_STASHED" - ) - - # The order that the prompt displays should be added to the prompt - local status_constants - status_constants=( - UNTRACKED ADDED MODIFIED RENAMED DELETED - STASHED UNMERGED AHEAD BEHIND DIVERGED - ) - - local status_text - status_text="$(__git_prompt_git status --porcelain -b 2> /dev/null)" - - # Don't continue on a catastrophic failure - if [[ $? -eq 128 ]]; then - return 1 - fi - - # A lookup table of each git status encountered - local -A statuses_seen - - if __git_prompt_git rev-parse --verify refs/stash &>/dev/null; then - statuses_seen[STASHED]=1 - fi - - local status_lines - status_lines=("${(@f)${status_text}}") - - # If the tracking line exists, get and parse it - if [[ "$status_lines[1]" =~ "^## [^ ]+ \[(.*)\]" ]]; then - local branch_statuses - branch_statuses=("${(@s/,/)match}") - for branch_status in $branch_statuses; do - if [[ ! $branch_status =~ "(behind|diverged|ahead) ([0-9]+)?" ]]; then - continue - fi - local last_parsed_status=$prefix_constant_map[$match[1]] - statuses_seen[$last_parsed_status]=$match[2] - done - fi - - # For each status prefix, do a regex comparison - for status_prefix in ${(k)prefix_constant_map}; do - local status_constant="${prefix_constant_map[$status_prefix]}" - local status_regex=$'(^|\n)'"$status_prefix" - - if [[ "$status_text" =~ $status_regex ]]; then - statuses_seen[$status_constant]=1 - fi - done - - # Display the seen statuses in the order specified - local status_prompt - for status_constant in $status_constants; do - if (( ${+statuses_seen[$status_constant]} )); then - local next_display=$constant_prompt_map[$status_constant] - status_prompt="$next_display$status_prompt" - fi - done - - echo $status_prompt -} - # Outputs the name of the current user # Usage example: $(git_current_user_name) function git_current_user_name() { -- cgit v1.2.3-70-g09d2 From f84341c57478445d534d0318231df8157ddfed3e Mon Sep 17 00:00:00 2001 From: tDwtp Date: Thu, 11 Dec 2025 15:05:23 +0100 Subject: fix(git): git_status_prompt should respect spaces in prefixes (#13478) --- lib/git.zsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/git.zsh') diff --git a/lib/git.zsh b/lib/git.zsh index f4d4229cb..8d38f3268 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -117,7 +117,7 @@ function _omz_git_prompt_status() { fi # For each status prefix, do a regex comparison - for status_prefix in ${(k)prefix_constant_map}; do + for status_prefix in "${(@k)prefix_constant_map}"; do local status_constant="${prefix_constant_map[$status_prefix]}" local status_regex=$'(^|\n)'"$status_prefix" -- cgit v1.2.3-70-g09d2