diff --git a/config/settings.conf b/config/settings.conf index e9f2552..c579acd 100644 --- a/config/settings.conf +++ b/config/settings.conf @@ -5,6 +5,7 @@ SBP_THEME_COLOR=${SBP_THEME_COLOR:-'default-256'} SBP_THEME_LAYOUT=${SBP_THEME_LAYOUT:-'plain'} # Default segment settings +SEGMENTS_GIT_GITSTATUS=${SEGMENTS_GIT_GITSTATUS:-"false"} SEGMENTS_K8S_DEFAULT_USER=${SEGMENTS_K8S_DEFAULT_USER:-"$USER"} SEGMENTS_K8S_HIDE_CLUSTER=${SEGMENTS_K8S_HIDE_CLUSTER:-0} SEGMENTS_LOAD_THRESHOLD=${SEGMENTS_LOAD_THRESHOLD:-50} diff --git a/config/settings.conf.template b/config/settings.conf.template index 4feab36..9106ecf 100644 --- a/config/settings.conf.template +++ b/config/settings.conf.template @@ -23,6 +23,7 @@ else fi # Segment specific settings +SEGMENTS_GIT_GITSTATUS='false' SEGMENTS_K8S_DEFAULT_USER="$USER" SEGMENTS_K8S_HIDE_CLUSTER=0 SEGMENTS_LOAD_THRESHOLD=50 diff --git a/sbp.bash b/sbp.bash index 8dca2b6..6c42f6f 100644 --- a/sbp.bash +++ b/sbp.bash @@ -15,6 +15,23 @@ else SBP_TMP=$(mktemp -d) && trap 'command rm -rf "$SBP_TMP"' EXIT; fi +# start gitstatus in the background if enabled +# shellcheck source=src/configure.bash +source "${SBP_PATH}/src/configure.bash" +configure::load_config + +if [[ $SEGMENTS_GIT_GITSTATUS ]]; then + if [[ -n ${GITSTATUS_DIR:-} ]]; then + source "$GITSTATUS_DIR" || return + elif [[ ${BASH_SOURCE[0]} == */* ]]; then + source "${BASH_SOURCE[0]%/*}/gitstatus.plugin.sh" || return + else + source gitstatus.plugin.sh || return + fi + + gitstatus_stop && gitstatus_start -s -1 -u -1 -c -1 -d -1 +fi + export SBP_TMP export SBP_PATH export COLUMNS @@ -39,10 +56,9 @@ _sbp_set_prompt() { title="${HOSTNAME:-ssh}:${title}" fi printf '\e]2;%s\007' "$title" - - PS1=$(bash "${SBP_PATH}/src/main.bash" "$command_status" "$command_duration") + # gitstatus.plugin.sh requires an interactive shell + PS1=$(bash --noediting --noprofile --norc -i "${SBP_PATH}/src/main.bash" "$command_status" "$command_duration" "$GITSTATUS_DIR" "$GITSTATUS_DAEMON_PID" "$_GITSTATUS_REQ_FD" "$_GITSTATUS_RESP_FD") [[ -n "$SBP_DEBUG" ]] && debug::tick_timer "Done" - } _sbp_pre_exec() { diff --git a/src/main.bash b/src/main.bash index a6d0bd2..8ba5642 100755 --- a/src/main.bash +++ b/src/main.bash @@ -1,4 +1,9 @@ -#! /usr/bin/env bash +#!/usr/bin/env bash + +# turn off history to not pollute the users history with our commands +# first turn of the history file to not add the set afterwards to it +export HISTFILE=/dev/null +set +o history # shellcheck source=src/debug.bash source "${SBP_PATH}/src/debug.bash" @@ -13,6 +18,10 @@ configure::load_config readonly COMMAND_EXIT_CODE=$1 readonly COMMAND_DURATION=$2 +readonly GITSTATUS_DIR=$3 +readonly GITSTATUS_DAEMON_PID=$4 +readonly _GITSTATUS_REQ_FD=$5 +readonly _GITSTATUS_RESP_FD=$6 main::main() { execute::execute_prompt_hooks diff --git a/src/segments/git.bash b/src/segments/git.bash index 9741518..c6a7a59 100644 --- a/src/segments/git.bash +++ b/src/segments/git.bash @@ -1,28 +1,6 @@ #! /usr/bin/env bash -segments::git() { - local max_length=$SEGMENTS_MAX_LENGTH - - local incoming_icon="${SEGMENTS_GIT_INCOMING_ICON:-↓}" - local outgoing_icon="${SEGMENTS_GIT_OUTGOING_ICON:-↑}" - - local branch_only="${SEGMENTS_GIT_BRANCH_ONLY:-false}" - - local path=${PWD} - while [[ $path ]]; do - if [[ -d "${path}/.git" ]]; then - local git_folder="${path}/.git" - break - fi - path=${path%/*} - done - - [[ -z "$git_folder" ]] && exit 0 - if [[ "$PWD" == "$git_folder" ]]; then - print_themed_segment 'normal' '.git/' - return 0 - fi - +segments::git::native() { if [[ "$branch_only" == false ]]; then local git_status="$(git status --porcelain --branch 2>/dev/null)" @@ -61,10 +39,11 @@ segments::git() { outgoing_filled="${upstream_stripped/ahead / ${outgoing_icon}}" upstream_status="${outgoing_filled/behind / ${incoming_icon}}" fi + ;; esac done <<< "$git_status" - local git_state="${additions_icon}${additions#0}${modifications_icon}${modifications#0}${deletions_icon}${deletions#0}${untracked_icon}${untracked#0}" + git_state="${additions_icon}${additions#0}${modifications_icon}${modifications#0}${deletions_icon}${deletions#0}${untracked_icon}${untracked#0}" # git status does not support detached head if [[ "$branch" != 'HEAD' ]]; then @@ -75,6 +54,75 @@ segments::git() { else git_head=$(git symbolic-ref --short HEAD 2>/dev/null || git rev-parse --short HEAD 2>/dev/null) fi +} + +segments::git::gitstatus() { + # TODO: keep the source from sbp.bash + if [[ -n ${GITSTATUS_DIR:-} ]]; then + source "$GITSTATUS_DIR" || return + elif [[ ${BASH_SOURCE[0]} == */* ]]; then + source "${BASH_SOURCE[0]%/*}/gitstatus.plugin.sh" || return + else + source gitstatus.plugin.sh || return + fi + + gitstatus_query "$@" || return 1 # error + [[ $VCS_STATUS_RESULT == ok-sync ]] || return 0 # not a git repo + + git_head="${VCS_STATUS_LOCAL_BRANCH:-${VCS_STATUS_TAG:-${VCS_STATUS_COMMIT:-}}}" + + if [[ "$branch_only" == false ]]; then + VCS_STATUS_DELETED=$((VCS_STATUS_NUM_STAGED_DELETED + VCS_STATUS_NUM_UNSTAGED_DELETED)) + + if [[ $VCS_STATUS_NUM_STAGED_NEW -gt 0 ]]; then + git_state=' +'${VCS_STATUS_NUM_STAGED_NEW#0} + fi + if [[ $VCS_STATUS_NUM_UNSTAGED -gt 0 ]]; then + git_state=$git_state' ~'${VCS_STATUS_NUM_UNSTAGED#0} + fi + if [[ $VCS_STATUS_DELETED -gt 0 ]]; then + git_state=$git_state' -'${VCS_STATUS_DELETED#0} + fi + if [[ $VCS_STATUS_NUM_UNTRACKED -gt 0 ]]; then + git_state=$git_state' ?'${VCS_STATUS_NUM_UNTRACKED#0} + fi + if [[ $VCS_STATUS_COMMITS_AHEAD -gt 0 ]]; then + upstream_status="$outgoing_icon$VCS_STATUS_COMMITS_AHEAD " + fi + if [[ $VCS_STATUS_COMMITS_BEHIND -gt 0 ]]; then + upstream_status="$upstream_status $incoming_icon$VCS_STATUS_COMMITS_BEHIND" + fi + fi +} + +segments::git() { + max_length=$SEGMENTS_MAX_LENGTH + + incoming_icon="${SEGMENTS_GIT_INCOMING_ICON:-↓}" + outgoing_icon="${SEGMENTS_GIT_OUTGOING_ICON:-↑}" + + branch_only="${SEGMENTS_GIT_BRANCH_ONLY:-false}" + + local path=${PWD} + while [[ $path ]]; do + if [[ -d "${path}/.git" ]]; then + local git_folder="${path}/.git" + break + fi + path=${path%/*} + done + + [[ -z "$git_folder" ]] && exit 0 + if [[ "$PWD" == "$git_folder" ]]; then + print_themed_segment 'normal' '.git/' + return 0 + fi + + if [[ $SEGMENTS_GIT_GITSTATUS == true ]]; then + segments::git::gitstatus + else + segments::git::native + fi git_size=$(( ${#git_state} + ${#SEGMENTS_GIT_ICON} + ${#git_head} + ${#upstream_status} ))