From f8165772ec1a25019a04fb6a0f4dcf8ec511eb01 Mon Sep 17 00:00:00 2001 From: Eric Nielsen Date: Wed, 15 Mar 2017 09:29:03 -0500 Subject: [PATCH 1/4] Add diverged context to git-info that, when defined, will be set if branch is both ahead and behind of remote. If not defined, the `ahead` and `behind` contexts will still be set, as how they worked previously. --- modules/git-info/README.md | 14 ++++++++++---- modules/git-info/init.zsh | 36 ++++++++++++++++++++++-------------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/modules/git-info/README.md b/modules/git-info/README.md index 956d540..ea0cc4b 100644 --- a/modules/git-info/README.md +++ b/modules/git-info/README.md @@ -48,16 +48,22 @@ a style is: | action | %s | Special action name (see Special Action Contexts below) | ahead | %A | Commits ahead of remote count | behind | %B | Commits behind of remote count +| diverged | %V | Diverged commits (both ahead and behind are yield when it's not defined) | branch | %b | Branch name | commit | %c | Commit short hash (when in 'detached HEAD' state) | clean | %C | Clean state -| dirty | %D | Dirty state (count with untracked files if verbose enabled) -| indexed | %i | Indexed files (count if verbose enabled) -| unindexed | %I | Unindexed files (count if verbose enabled) +| dirty | %D | Dirty state (count with untracked files when verbose mode enabled) +| indexed | %i | Indexed files (count when verbose mode enabled) +| unindexed | %I | Unindexed files (count when verbose mode enabled) | position | %p | Commits from nearest tag count (when in 'detached HEAD' state) | remote | %R | Remote name | stashed | %S | Stashed states count -| untracked | %u | Untracked files count (only if verbose enabled) +| untracked | %u | Untracked files count (only when verbose mode enabled) + +While `commit` and `position` are only available when in ['detached HEAD' +state](http://gitfaq.org/articles/what-is-a-detached-head.html), on the other +hand, `ahead`, `behind`, `diverged`, `branch` and `remote` are only available +when an actual branch is checked out (so when **not** in 'detached HEAD' state). ### Special Action Contexts diff --git a/modules/git-info/init.zsh b/modules/git-info/init.zsh index 1b4d16c..e410ab4 100644 --- a/modules/git-info/init.zsh +++ b/modules/git-info/init.zsh @@ -5,7 +5,7 @@ # Gets the Git special action (am, bisect, cherry, merge, rebase). # Borrowed from vcs_info and edited. -function _git-action { +_git-action() { local git_dir=$(git-dir) local action_dir for action_dir in \ @@ -87,7 +87,7 @@ function _git-action { } # Gets the Git status information. -function git-info { +git-info() { # Extended globbing is needed to parse repository status. setopt LOCAL_OPTIONS EXTENDED_GLOB @@ -148,6 +148,7 @@ function git-info { local behind_formatted local branch_formatted local commit_formatted + local diverged_formatted local position_formatted local remote_formatted if [[ -n ${branch} ]]; then @@ -172,25 +173,31 @@ function git-info { local ahead_format local behind_format + local diverged_format zstyle -s ':zim:git-info:ahead' format 'ahead_format' zstyle -s ':zim:git-info:behind' format 'behind_format' - if [[ -n ${ahead_format} || -n ${behind_format} ]]; then + zstyle -s ':zim:git-info:diverged' format 'diverged_format' + if [[ -n ${ahead_format} || -n ${behind_format} || -n ${diverged_format} ]]; then # Gets the commit difference counts between local and remote. local ahead_and_behind_cmd='git rev-list --count --left-right HEAD...@{upstream}' # Get ahead and behind counts. local ahead_and_behind=$(${(z)ahead_and_behind_cmd} 2>/dev/null) + local ahead=${ahead_and_behind[(w)1]} + local behind=${ahead_and_behind[(w)2]} - # Format ahead. - if [[ -n ${ahead_format} ]]; then - local ahead=${ahead_and_behind[(w)1]} - (( ahead )) && zformat -f ahead_formatted ${ahead_format} "A:${ahead}" - fi - - # Format behind. - if [[ -n ${behind_format} ]]; then - local behind=${ahead_and_behind[(w)2]} - (( behind )) && zformat -f behind_formatted ${behind_format} "B:${behind}" + if [[ -n ${diverged_format} && ${ahead} -gt 0 && ${behind} -gt 0 ]]; then + # Format diverged. + diverged_formatted=${diverged_format} + else + # Format ahead. + if [[ -n ${ahead_format} && ${ahead} -gt 0 ]]; then + zformat -f ahead_formatted ${ahead_format} "A:${ahead}" + fi + # Format behind. + if [[ -n ${behind_format} && ${behind} -gt 0 ]]; then + zformat -f behind_formatted ${behind_format} "B:${behind}" + fi fi fi else @@ -328,7 +335,8 @@ function git-info { "R:${remote_formatted}" \ "s:${action_formatted}" \ "S:${stashed_formatted}" \ - "u:${untracked_formatted}" + "u:${untracked_formatted}" \ + "V:${diverged_formatted}" git_info[${info_format}]=${reply} done From 96d6b66de12c5b50558df9cb503df07778fb6584 Mon Sep 17 00:00:00 2001 From: Eric Nielsen Date: Wed, 15 Mar 2017 09:36:02 -0500 Subject: [PATCH 2/4] Remove undocumented git-info configuration `prompt.showinfo` for enabling or disabling it globally or per repository. It can be globally disabled by not loading the `git-info` module at all, and prompts currently will not break (and in the future should still not break) if the module is not loaded. This removes one git call that is used to check for the `prompt.showinfo` configuration value. --- modules/git-info/init.zsh | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/modules/git-info/init.zsh b/modules/git-info/init.zsh index e410ab4..9043208 100644 --- a/modules/git-info/init.zsh +++ b/modules/git-info/init.zsh @@ -100,22 +100,6 @@ git-info() { return 1 fi - if (( $# )); then - if [[ $1 == [Oo][Nn] ]]; then - git config --bool prompt.showinfo true - elif [[ $1 == [Oo][Ff][Ff] ]]; then - git config --bool prompt.showinfo false - else - print "usage: $0 [ on | off ]" >&2 - fi - return 0 - fi - - # Return if git-info is disabled. - if ! is-true ${$(git config --bool prompt.showinfo):-true}; then - return 1 - fi - # Ignore submodule status. local ignore_submodules zstyle -s ':zim:git-info' ignore-submodules 'ignore_submodules' || ignore_submodules='all' From d440135f52e2afe7ce9959d5883a9de310a06a73 Mon Sep 17 00:00:00 2001 From: Eric Nielsen Date: Wed, 15 Mar 2017 09:40:22 -0500 Subject: [PATCH 3/4] Add coalesce function to git-info that will be used by the minimal theme, and could be used for future themes too. Prezto had this, but we diminished its necessity by simplifying how git-info works. --- modules/git-info/functions/coalesce | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 modules/git-info/functions/coalesce diff --git a/modules/git-info/functions/coalesce b/modules/git-info/functions/coalesce new file mode 100644 index 0000000..e9e838e --- /dev/null +++ b/modules/git-info/functions/coalesce @@ -0,0 +1,6 @@ +# Prints the first non-empty string in the arguments array. +for arg in ${argv}; do + print -n ${arg} + return 0 +done +return 1 From b1231ed516e5eaae1c2f736f0ae47b88804deeb9 Mon Sep 17 00:00:00 2001 From: Eric Nielsen Date: Wed, 15 Mar 2017 09:43:35 -0500 Subject: [PATCH 4/4] Rewrite minimal theme using git-info As previous migrations of themes to git-info, this does not use its verbose mode, so a repo with just untracked files is not considered dirty. It uses the newly-introduced `diverged` context and `coalesce` function from git-info. --- modules/prompt/themes/minimal.zsh-theme | 108 +++++++++++------------- 1 file changed, 49 insertions(+), 59 deletions(-) diff --git a/modules/prompt/themes/minimal.zsh-theme b/modules/prompt/themes/minimal.zsh-theme index 839a790..d88cd98 100644 --- a/modules/prompt/themes/minimal.zsh-theme +++ b/modules/prompt/themes/minimal.zsh-theme @@ -2,97 +2,87 @@ # Minimal theme # https://github.com/S1cK94/minimal # +# Requires the `git-info` zmodule to be included in the .zimrc file. -minimal_user() { - print "%(!.$on_color.$off_color)$prompt_char%f" +# Global variables +function { + PROMPT_CHAR='❯' + + ON_COLOR='%F{green}' + OFF_COLOR='%f' + ERR_COLOR='%F{red}' } -minimal_jobs() { - print "%(1j.$on_color.$off_color)$prompt_char%f" +prompt_minimal_user() { + print -n '%(!.${ON_COLOR}.${OFF_COLOR})${PROMPT_CHAR}' } -minimal_vimode(){ - local ret="" +prompt_minimal_jobs() { + print -n '%(1j.${ON_COLOR}.${OFF_COLOR})${PROMPT_CHAR}' +} - case $KEYMAP in +prompt_minimal_vimode() { + local color + + case ${KEYMAP} in main|viins) - ret+="$on_color" + color=${ON_COLOR} ;; - vicmd) - ret+="$off_color" + *) + color=${OFF_COLOR} ;; esac - ret+="$prompt_char%f" - - print "$ret" + print -n "${color}${PROMPT_CHAR}" } -minimal_status() { - print "%(0?.$on_color.$err_color)$prompt_char%f" +prompt_minimal_status() { + print -n '%(0?.${ON_COLOR}.${ERR_COLOR})${PROMPT_CHAR}' } -minimal_path() { - local path_color="%F{244}" - local rsc="%f" - local sep="$rsc/$path_color" - - print "$path_color$(sed s_/_${sep}_g <<< $(short_pwd))$rsc" +prompt_minimal_path() { + local path_color='%F{244}' + print -n "${path_color}${$(short_pwd)//\//%f\/${path_color}}%f" } -git_branch_name() { - local branch_name="$(command git rev-parse --abbrev-ref HEAD 2> /dev/null)" - [[ -n $branch_name ]] && print "$branch_name" -} - -git_repo_status(){ - local rs="$(command git status --porcelain -b)" - - if $(print "$rs" | grep -v '^##' &> /dev/null); then # is dirty - print "%F{red}" - elif $(print "$rs" | grep '^## .*diverged' &> /dev/null); then # has diverged - print "%F{red}" - elif $(print "$rs" | grep '^## .*behind' &> /dev/null); then # is behind - print "%F{11}" - elif $(print "$rs" | grep '^## .*ahead' &> /dev/null); then # is ahead - print "%f" - else # is clean - print "%F{green}" +prompt_minimal_git() { + if [[ -n ${git_info} ]]; then + print -n " ${(e)git_info[color]}${(e)git_info[prompt]}" fi } -minimal_git() { - local bname=$(git_branch_name) - if [[ -n ${bname} ]]; then - local infos="$(git_repo_status)${bname}%f" - print " $infos" - fi -} - -function zle-line-init zle-line-finish zle-keymap-select { +function zle-line-init zle-keymap-select { zle reset-prompt zle -R } prompt_minimal_precmd() { - zle -N zle-line-init - zle -N zle-keymap-select - zle -N zle-line-finish - - PROMPT='$(minimal_user)$(minimal_jobs)$(minimal_vimode)$(minimal_status) ' - RPROMPT='$(minimal_path)$(minimal_git)' + (( ${+functions[git-info]} )) && git-info } prompt_minimal_setup() { - prompt_char="❯" - on_color="%F{green}" - off_color="%f" - err_color="%F{red}" + zle -N zle-line-init + zle -N zle-keymap-select + autoload -Uz colors && colors autoload -Uz add-zsh-hook + prompt_opts=(cr percent subst) + add-zsh-hook precmd prompt_minimal_precmd - prompt_opts=(cr subst percent) + + zstyle ':zim:git-info:branch' format '%b' + zstyle ':zim:git-info:commit' format '%c' + zstyle ':zim:git-info:dirty' format '${ERR_COLOR}' + zstyle ':zim:git-info:diverged' format '${ERR_COLOR}' + zstyle ':zim:git-info:behind' format '%F{11}' + zstyle ':zim:git-info:ahead' format '${OFF_COLOR}' + zstyle ':zim:git-info:keys' format \ + 'prompt' '%b%c' \ + 'color' '$(coalesce "%D" "%V" "%B" "%A" "${ON_COLOR}")' + + PROMPT="$(prompt_minimal_user)$(prompt_minimal_jobs)\$(prompt_minimal_vimode)$(prompt_minimal_status)%f " + RPROMPT='$(prompt_minimal_path)$(prompt_minimal_git)' } prompt_minimal_setup "$@"