diff options
Diffstat (limited to 'hyperterm/core/git.sh')
-rw-r--r-- | hyperterm/core/git.sh | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/hyperterm/core/git.sh b/hyperterm/core/git.sh new file mode 100644 index 0000000..17bb575 --- /dev/null +++ b/hyperterm/core/git.sh @@ -0,0 +1,332 @@ +#!/bin/bash + +# Set up symbols +function _symbols() { + + # Import colors + _colors_bash "$@" + + _synced_symbol="$(printf '%b\u2714' "${BOLD}${CYAN}")" # ✔ + _dirty_synced_symbol="$(printf '%b\u002A' "${BOLD}${RED}")" # ∗ + _unpushed_symbol="$(printf '%b\u2191' "${BOLD}${CYAN}")" # ↑ + _dirty_unpushed_symbol="$(printf '%b\u25B2' "${BOLD}${YELLOW}")" # ▲ + _unpulled_symbol="$(printf '%b\u25BD' "${BOLD}${GREEN}")" # ▽ + _dirty_unpulled_symbol="$(printf '%b\u25BC' "${BOLD}${RED}")" # ▼ + _stage_symbol="$(printf '%b\u2192\u004D' "${BOLD}${CYAN}")" # →M + _unstage_symbol="$(printf '%b\u2190\u004D' "${BOLD}${RED}")" # ←M + _untracked_symbol="$(printf '%b\u003F' "${BOLD}${RED}")" # ? + _newfile_symbol="$(printf '%b\u002B' "${BOLD}${CYAN}")" # + + _deleted_file_symbol="$(printf '%b\u2013' "${BOLD}${RED}")" # – + _renamed_symbol="$(printf '%b\u2387 ' "${BOLD}${RED}")" # ⎇ + _unpushed_unpulled_symbol="$(printf '%b\u2B21' "${BOLD}${RED}")" # ⬡ + _dirty_unpushed_unpulled_symbol="$(printf '%b\u2B22' "${BOLD}${RED}")" # ⬢ +} + +function _get_git_branch() { + # On branches, this will return the branch name + # On non-branches, (no branch) + ref="$(git symbolic-ref HEAD 2> /dev/null | sed -e 's/refs\/heads\///')" + if [[ -n $ref ]]; then + printf '%s' "$ref" + else + printf "(no branch)" + fi +} + +function _get_git_progress() { + # Detect in-progress actions (e.g. merge, rebase) + # https://github.com/git/git/blob/v1.9-rc2/wt-status.c#L1199-L1241 + git_dir="$(git rev-parse --git-dir)" + + # git merge + if [[ -f "$git_dir/MERGE_HEAD" ]]; then + printf " [merge]" + elif [[ -d "$git_dir/rebase-apply" ]]; then + # git am + if [[ -f "$git_dir/rebase-apply/applying" ]]; then + printf " [am]" + # git rebase + else + printf " [rebase]" + fi + elif [[ -d "$git_dir/rebase-merge" ]]; then + # git rebase --interactive/--merge + printf " [rebase]" + elif [[ -f "$git_dir/CHERRY_PICK_HEAD" ]]; then + # git cherry-pick + printf " [cherry-pick]" + fi + if [[ -f "$git_dir/BISECT_LOG" ]]; then + # git bisect + printf " [bisect]" + fi + if [[ -f "$git_dir/REVERT_HEAD" ]]; then + # git revert --no-commit + printf " [revert]" + fi +} + +_prompt_is_branch1_behind_branch2 () { + # $ git log origin/master..master -1 + # commit 4a633f715caf26f6e9495198f89bba20f3402a32 + # Author: Todd Wolfson <todd@twolfson.com> + # Date: Sun Jul 7 22:12:17 2013 -0700 + # + # Unsynced commit + + # Find the first log (if any) that is in branch1 but not branch2 + first_log="$(git log "$1..$2" -1 2> /dev/null)" + + # Exit with 0 if there is a first log, 1 if there is not + [[ -n "$first_log" ]] +} + +_prompt_branch_exists () { + # List remote branches | # Find our branch and exit with 0 or 1 if found/not found + git branch --remote 2> /dev/null | grep --quiet "$1" +} + +_prompt_parse_git_ahead () { + # Grab the local and remote branch + branch="$(_get_git_branch)" + remote="$(git config --get "branch.${branch}.remote" || echo -n "origin")" + remote_branch="$remote/$branch" + + # $ git log origin/master..master + # commit 4a633f715caf26f6e9495198f89bba20f3402a32 + # Author: Todd Wolfson <todd@twolfson.com> + # Date: Sun Jul 7 22:12:17 2013 -0700 + # + # Unsynced commit + + # If the remote branch is behind the local branch + # or it has not been merged into origin (remote branch doesn't exist) + if (_prompt_is_branch1_behind_branch2 "$remote_branch" "$branch" || + ! _prompt_branch_exists "$remote_branch"); then + # printf our character + printf '%s' '0' + fi +} + +_prompt_parse_git_behind() { + # Grab the branch + branch="$(_get_git_branch)" + remote="$(git config --get "branch.${branch}.remote" || echo -n "origin")" + remote_branch="$remote/$branch" + + # $ git log master..origin/master + # commit 4a633f715caf26f6e9495198f89bba20f3402a32 + # Author: Todd Wolfson <todd@twolfson.com> + # Date: Sun Jul 7 22:12:17 2013 -0700 + # + # Unsynced commit + + # If the local branch is behind the remote branch + if _prompt_is_branch1_behind_branch2 "$branch" "$remote_branch"; then + # printf our character + printf '%s' '0' + fi +} + +function _prompt_parse_git_dirty() { + # If the git status has *any* changes (e.g. dirty), printf our character + if [[ -n "$(git status --porcelain 2> /dev/null)" ]]; then + printf '%s' '0' + fi +} + +# start counter on git +function _git_dirty_count() { + local _dirty_status + local _git_status + _dirty_status="$(_prompt_parse_git_dirty)" + _git_status="$(git status --porcelain 2> /dev/null)" + if [[ "$_dirty_status" == 0 ]]; then + local change_count + change_count="$(echo "$_git_status" | wc -l | tr -d '[:space:]')" + if [[ "$change_count" == 1 ]]; then + printf '%b\u2022%s' "${BOLD}${GREY}" "$change_count" + elif [[ "$change_count" == 2 ]]; then + printf '%b\u2236%s' "${BOLD}${GREY}" "$change_count" + elif [[ "$change_count" == 3 ]]; then + printf '%b\u2026%s' "${BOLD}${GREY}" "$change_count" + else + printf '%b\u00BB%s' "${BOLD}${GREY}" "$change_count" + fi + else + printf '' + fi +} +# ends counter on git + +function _prompt_parse_git_untracked() { + local untracked + local evaltask + untracked="$(git status 2>&1 | tee)" + grep -E 'Untracked files:' <<<"$untracked" &> /dev/null + evaltask=$? + if [ "$evaltask" -eq 0 ]; then + printf '%s' '0' + else + printf '%s' '1' + fi +} + +function _prompt_parse_git_newfile() { + local newfile + local evaltask + newfile="$(git status 2>&1 | tee)" + grep -E 'new file:' <<<"$newfile" &> /dev/null + evaltask=$? + if [ "$evaltask" -eq 0 ]; then + printf '%s' '0' + else + printf '%s' '1' + fi +} + +function _prompt_parse_git_deleted_file() { + local deleted_file + local evaltask + deleted_file="$(git status 2>&1 | tee)" + grep -E 'deleted:' <<<"$deleted_file" &> /dev/null + evaltask=$? + if [ "$evaltask" -eq 0 ]; then + printf '%s' '0' + else + printf '%s' '1' + fi +} + +function _prompt_parse_git_renamed() { + local renamed + local evaltask + renamed="$(git status 2>&1 | tee)" + grep -E 'renamed:' <<<"$renamed" &> /dev/null + evaltask=$? + if [ "$evaltask" -eq 0 ]; then + printf '%s' '0' + else + printf '%s' '1' + fi +} + +function _prompt_parse_git_unstage() { + local unstage + local evaltask + unstage="$(git status 2>&1 | tee)" + grep -E 'not staged' <<<"$unstage" &> /dev/null + evaltask=$? + if [ "$evaltask" -eq 0 ]; then + printf '%s' '0' + else + printf '%s' '1' + fi +} + +function _prompt_parse_git_stage() { + local stage + local evaltask + stage="$(git status -s 2>&1 | tee)" + grep -E 'M' <<<"$stage" &> /dev/null + evaltask=$? + if [ "$evaltask" -eq 0 ]; then + printf '%s' '0' + else + printf '%s' '1' + fi +} + +function _prompt_is_on_git() { + git rev-parse 2> /dev/null +} + +function _prompt_get_git_status() { + + _symbols "$@" + + # Grab the git dirty and git behind + git_count="$(_git_dirty_count)" + dirty_branch="$(_prompt_parse_git_dirty)" + branch_ahead="$(_prompt_parse_git_ahead)" + branch_behind="$(_prompt_parse_git_behind)" + branch_stage="$(_prompt_parse_git_stage)" + branch_unstage="$(_prompt_parse_git_unstage)" + branch_untracked="$(_prompt_parse_git_untracked)" + branch_newfile="$(_prompt_parse_git_newfile)" + branch_deleted_file="$(_prompt_parse_git_deleted_file)" + branch_renamed="$(_prompt_parse_git_renamed)" + + # Iterate through all the cases and if it matches, then printf + if [[ "$dirty_branch" == 0 && "$branch_ahead" == 0 && "$branch_behind" == 0 ]]; then + printf '%s%s' "$_dirty_unpushed_unpulled_symbol" "$git_count" + + elif [[ "$branch_ahead" == 0 && "$branch_behind" == 0 ]]; then + printf '%s%s' "$_unpushed_unpulled_symbol" "$git_count" + + elif [[ "$dirty_branch" == 0 && "$branch_ahead" == 0 ]]; then + printf '%s%s' "$_dirty_unpushed_symbol" "$git_count" + + elif [[ "$branch_ahead" == 0 ]]; then + printf '%s%s' "$_unpushed_symbol" "$git_count" + + elif [[ "$dirty_branch" == 0 && "$branch_behind" == 0 ]]; then + printf '%s%s' "$_dirty_unpulled_symbol" "$git_count" + + elif [[ "$branch_behind" == 0 ]]; then + printf '%s%s' "$_unpulled_symbol" "$git_count" + + elif [[ "$branch_unstage" == 0 && "$branch_untracked" == 0 ]]; then + printf '%s%s' "${_unstage_symbol}${_untracked_symbol}" "$git_count" + + elif [[ "$branch_stage" == 0 && "$branch_untracked" == 0 ]]; then + printf '%s%s' "${_stage_symbol}${_untracked_symbol}" "$git_count" + + elif [[ "$branch_stage" == 0 && "$branch_unstage" == 0 ]]; then + printf '%s%s' "$_unstage_symbol" "$git_count" + + elif [[ "$branch_newfile" == 0 && "$branch_untracked" == 0 ]]; then + printf '%s%s' "${_newfile_symbol}${_untracked_symbol}" "$git_count" + + elif [[ "$branch_untracked" == 0 ]]; then + printf '%s%s' "$_untracked_symbol" "$git_count" + + elif [[ "$branch_stage" == 0 ]]; then + printf '%s%s' "$_stage_symbol" "$git_count" + + elif [[ "$branch_newfile" == 0 ]]; then + printf '%s%s' "$_newfile_symbol" "$git_count" + + elif [[ "$branch_deleted_file" == 0 ]]; then + printf '%s%s' "$_deleted_file_symbol" "$git_count" + + elif [[ "$branch_renamed" == 0 ]]; then + printf '%s%s' "$_renamed_symbol" "$git_count" + + elif [[ "$dirty_branch" == 0 ]]; then + printf '%s%s' "$_dirty_synced_symbol" "$git_count" + + else # clean + printf '%s' "$_synced_symbol" + fi +} + +_prompt_get_git_info() { + # Import colors + _colors_bash "$@" + + # Grab the branch + branch="$(_get_git_branch)" + + # If there are any branches + if [[ -n $branch ]]; then + # Printf the branch + output="$branch" + + # Add on the git status + output="$output$(_prompt_get_git_status "$@")" + + # Printf our output + printf '%b%s%b' "${BOLD}${LEMON}" "git:($output" "${BOLD}${LEMON})" + fi +} |