From 3fa088128157d99aebad87674196c46397817924 Mon Sep 17 00:00:00 2001 From: Christophe Aguettaz Date: Mon, 25 Jan 2016 20:02:50 +0100 Subject: [PATCH 1/2] [bugfix] Fixed performance issue with git prompt The git prompt would could bash to use 100% CPU for large amounts of time when dealing with long `git status` outputs. --- themes/base.theme.bash | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/themes/base.theme.bash b/themes/base.theme.bash index c491e5e5..962df15a 100644 --- a/themes/base.theme.bash +++ b/themes/base.theme.bash @@ -92,19 +92,48 @@ function scm_prompt_info { [[ $SCM == $SCM_SVN ]] && svn_prompt_info && return } +function git_status_summary { + awk ' + { + if (!after_first && $0 ~ /^##.+/) { + print $0 + seen_header = 1 + } else if ($0 ~ /^\?\? .+/) { + untracked += 1 + } else { + if ($0 ~ /^.[^ ] .+/) { + unstaged += 1 + } + if ($0 ~ /^[^ ]. .+/) { + staged += 1 + } + } + after_first = 1 + } + END { + if (!seen_header) { + print + } + print untracked + print unstaged + print staged + }' +} + function git_prompt_vars { local details='' SCM_STATE=${GIT_THEME_PROMPT_CLEAN:-$SCM_THEME_PROMPT_CLEAN} if [[ "$(git config --get bash-it.hide-status)" != "1" ]]; then [[ "${SCM_GIT_IGNORE_UNTRACKED}" = "true" ]] && local git_status_flags='-uno' - local status="$(git status -b --porcelain ${git_status_flags} 2> /dev/null || - git status --porcelain ${git_status_flags} 2> /dev/null)" - if [[ -n "${status}" ]] && [[ "${status}" != "\n" ]] && [[ -n "$(grep -v ^# <<< "${status}")" ]]; then + readarray -t status_lines < <((git status --porcelain ${git_status_flags} -b 2> /dev/null || + git status --porcelain ${git_status_flags} 2> /dev/null) | git_status_summary ) + local status="${status_lines[0]}" + local untracked_count="${status_lines[1]}" + local unstaged_count="${status_lines[2]}" + local staged_count="${status_lines[3]}" + if [[ "${untracked_count}" -gt 0 || "${unstaged_count}" -gt 0 || "${staged_count}" -gt 0 ]]; then SCM_DIRTY=1 if [[ "${SCM_GIT_SHOW_DETAILS}" = "true" ]]; then - local untracked_count="$(egrep -c '^\?\? .+' <<< "${status}")" - local unstaged_count="$(egrep -c '^.[^ ?#] .+' <<< "${status}")" - local staged_count="$(egrep -c '^[^ ?#]. .+' <<< "${status}")" [[ "${staged_count}" -gt 0 ]] && details+=" ${SCM_GIT_STAGED_CHAR}${staged_count}" && SCM_DIRTY=3 [[ "${unstaged_count}" -gt 0 ]] && details+=" ${SCM_GIT_UNSTAGED_CHAR}${unstaged_count}" && SCM_DIRTY=2 [[ "${untracked_count}" -gt 0 ]] && details+=" ${SCM_GIT_UNTRACKED_CHAR}${untracked_count}" && SCM_DIRTY=1 From a2ac5b0096c41212730995b5d0e67d8713655e8f Mon Sep 17 00:00:00 2001 From: Christophe Aguettaz Date: Tue, 26 Jan 2016 20:05:47 +0100 Subject: [PATCH 2/2] Fixed compatibility with older bash versions. Older versions (like 3.2, current default on MacOS X) don't implement readarray. --- themes/base.theme.bash | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/themes/base.theme.bash b/themes/base.theme.bash index 962df15a..ee906dee 100644 --- a/themes/base.theme.bash +++ b/themes/base.theme.bash @@ -114,9 +114,7 @@ function git_status_summary { if (!seen_header) { print } - print untracked - print unstaged - print staged + print untracked "\t" unstaged "\t" staged }' } @@ -125,12 +123,11 @@ function git_prompt_vars { SCM_STATE=${GIT_THEME_PROMPT_CLEAN:-$SCM_THEME_PROMPT_CLEAN} if [[ "$(git config --get bash-it.hide-status)" != "1" ]]; then [[ "${SCM_GIT_IGNORE_UNTRACKED}" = "true" ]] && local git_status_flags='-uno' - readarray -t status_lines < <((git status --porcelain ${git_status_flags} -b 2> /dev/null || - git status --porcelain ${git_status_flags} 2> /dev/null) | git_status_summary ) - local status="${status_lines[0]}" - local untracked_count="${status_lines[1]}" - local unstaged_count="${status_lines[2]}" - local staged_count="${status_lines[3]}" + local status_lines=$((git status --porcelain ${git_status_flags} -b 2> /dev/null || + git status --porcelain ${git_status_flags} 2> /dev/null) | git_status_summary) + local status=$(awk 'NR==1' <<< "$status_lines") + local counts=$(awk 'NR==2' <<< "$status_lines") + IFS=$'\t' read untracked_count unstaged_count staged_count <<< "$counts" if [[ "${untracked_count}" -gt 0 || "${unstaged_count}" -gt 0 || "${staged_count}" -gt 0 ]]; then SCM_DIRTY=1 if [[ "${SCM_GIT_SHOW_DETAILS}" = "true" ]]; then