-
-
Save oli/7686885 to your computer and use it in GitHub Desktop.
# vim:ft=zsh ts=2 sw=2 sts=2 | |
# | |
# agnoster's Theme - https://gist.github.com/3712874 | |
# A Powerline-inspired theme for ZSH | |
# | |
# # README | |
# | |
# In order for this theme to render correctly, you will need a | |
# [Powerline-patched font](https://github.com/Lokaltog/powerline-fonts). | |
# | |
# In addition, I recommend the | |
# [Solarized theme](https://github.com/altercation/solarized/) and, if you're | |
# using it on Mac OS X, [iTerm 2](http://www.iterm2.com/) over Terminal.app - | |
# it has significantly better color fidelity. | |
# | |
# # Goals | |
# | |
# The aim of this theme is to only show you *relevant* information. Like most | |
# prompts, it will only show git information when in a git working directory. | |
# However, it goes a step further: everything from the current user and | |
# hostname to whether the last call exited with an error to whether background | |
# jobs are running in this shell will all be displayed automatically when | |
# appropriate. | |
### Segment drawing | |
# A few utility functions to make it easy and re-usable to draw segmented prompts | |
CURRENT_BG='NONE' | |
PRIMARY_FG=black | |
# Characters | |
SEGMENT_SEPARATOR="\ue0b0" | |
PLUSMINUS="\u00b1" | |
BRANCH="\ue0a0" | |
DETACHED="\u27a6" | |
CROSS="\u2718" | |
LIGHTNING="\u26a1" | |
GEAR="\u2699" | |
# Begin a segment | |
# Takes two arguments, background and foreground. Both can be omitted, | |
# rendering default background/foreground. | |
prompt_segment() { | |
local bg fg | |
[[ -n $1 ]] && bg="%K{$1}" || bg="%k" | |
[[ -n $2 ]] && fg="%F{$2}" || fg="%f" | |
if [[ $CURRENT_BG != 'NONE' && $1 != $CURRENT_BG ]]; then | |
print -n " %{$bg%F{$CURRENT_BG}%}$SEGMENT_SEPARATOR%{$fg%} " | |
else | |
print -n "%{$bg%}%{$fg%} " | |
fi | |
CURRENT_BG=$1 | |
[[ -n $3 ]] && print -n $3 | |
} | |
# End the prompt, closing any open segments | |
prompt_end() { | |
if [[ -n $CURRENT_BG ]]; then | |
print -n " %{%k%F{$CURRENT_BG}%}$SEGMENT_SEPARATOR" | |
else | |
print -n "%{%k%}" | |
fi | |
print -n "%{%f%}" | |
CURRENT_BG='' | |
} | |
### Prompt components | |
# Each component will draw itself, and hide itself if no information needs to be shown | |
# Context: user@hostname (who am I and where am I) | |
prompt_context() { | |
local user=`whoami` | |
if [[ "$user" != "$DEFAULT_USER" || -n "$SSH_CONNECTION" ]]; then | |
prompt_segment $PRIMARY_FG default " %(!.%{%F{yellow}%}.)$user@%m " | |
fi | |
} | |
# Git: branch/detached head, dirty status | |
# Prompt additions from @oli, ref: https://gist.github.com/oli/7686885 | |
# Kinda synced to https://github.com/robbyrussell/oh-my-zsh/commit/74177c5320b2a1b2f8c4c695c05984b57fd7c6ea | |
prompt_git() { | |
local ref dirty | |
if $(git rev-parse --is-inside-work-tree >/dev/null 2>&1); then | |
# from parse_git_dirty | |
# needs to be present and have content or an asterisk is added | |
# however not displayed because $dirty isn’t in prompt | |
ZSH_THEME_GIT_PROMPT_DIRTY='±' | |
# from git_prompt_status | |
ZSH_THEME_GIT_PROMPT_STASHED='↯ ' | |
ZSH_THEME_GIT_PROMPT_UNTRACKED='?' | |
# these are covered by (un)stagedstr, which I can’t hide. sigh | |
#ZSH_THEME_GIT_PROMPT_ADDED='+' | |
#ZSH_THEME_GIT_PROMPT_MODIFIED='±' | |
#ZSH_THEME_GIT_PROMPT_RENAMED='~' | |
#ZSH_THEME_GIT_PROMPT_DELETED='-' | |
# 2013-11-19 add remote status | |
# ref: https://github.com/somacreates/etc/blob/master/agnoster.zsh-theme →404 | |
# from git_remote_status | |
ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE="↑" | |
ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE="↓" | |
ZSH_THEME_GIT_PROMPT_DIVERGED_REMOTE="↕" | |
# from git.zsh: | |
# get the difference between the local and remote branches | |
remote=$(git_remote_status) | |
# Checks if working tree is dirty | |
dirty=$(parse_git_dirty) | |
# Get the status of the working tree | |
gps=$(git_prompt_status) | |
# Get branch name | |
ref=$(git symbolic-ref HEAD 2> /dev/null) || ref="➦ $(git rev-parse --short HEAD 2> /dev/null)" | |
# change prompt background based on status | |
# unmerged remote changes, local commits | |
# note: $remote has to be before $dirty to work (why?) | |
if [[ "$remote" == "$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE" ]] && [[ "$dirty" == "$ZSH_THEME_GIT_PROMPT_DIRTY" ]]; then | |
prompt_segment red $PRIMARY_FG | |
# unmerged remote changes | |
elif [[ "$remote" == "$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE" ]]; then | |
prompt_segment magenta $PRIMARY_FG | |
# local commits | |
elif [[ -n $remote ]]; then | |
prompt_segment yellow $PRIMARY_FG | |
# local changes | |
elif [[ -n $dirty ]]; then | |
prompt_segment cyan $PRIMARY_FG | |
else | |
prompt_segment green $PRIMARY_FG | |
fi | |
setopt promptsubst | |
autoload -Uz vcs_info() | |
# http://youam.net/misc/zsh/vcs_info.html | |
zstyle ':vcs_info:*' enable git | |
zstyle ':vcs_info:*' get-revision true | |
zstyle ':vcs_info:*' check-for-changes true | |
zstyle ':vcs_info:*' stagedstr '◯' # staged changes | |
zstyle ':vcs_info:git:*' unstagedstr '±' # unstaged changes | |
zstyle ':vcs_info:*' formats ' %u%c' | |
zstyle ':vcs_info:*' actionformats ' %u%c' | |
vcs_info | |
echo -n "${ref/refs\/heads\// } $gps${vcs_info_msg_0_%% } $remote" | |
fi | |
} | |
# Dir: current working directory | |
# 2014-12-01 Change to truncated: | |
# trim directories to first 2 and last 3 if >6 directories in path | |
# from http://rockhopper.dk/linux/zsh-promptwindow-title-trim-middle-of-path/ | |
# Responsive prompt from https://www.alexscotton.com/post/a-modular-responsive-zsh-theme-and-some-bonus-unix-commands | |
# TODO would be nice to cap prompt to $COLUMNS (terminal width) | |
prompt_dir() { | |
# prompt_segment blue $PRIMARY_FG ' %~ ' | |
if [[ ${COLUMNS} -gt 110 ]]; then | |
prompt_segment blue $PRIMARY_FG ' %8(c:%-3~/.../%4~:%~) ' | |
elif [[ ${COLUMNS} -gt 90 ]]; then | |
prompt_segment blue $PRIMARY_FG ' %7(c:%-3~/.../%3~:%~) ' | |
elif [[ ${COLUMNS} -gt 75 ]]; then | |
prompt_segment blue $PRIMARY_FG ' %7(c:%-3~/.../%2~:%~) ' | |
else | |
prompt_segment blue $PRIMARY_FG ' %6(c:%-2~/.../%2~:%~) ' | |
fi | |
} | |
# Virtualenv: current working virtualenv | |
prompt_virtualenv() { | |
local virtualenv_path="$VIRTUAL_ENV" | |
if [[ -n $virtualenv_path && -n $VIRTUAL_ENV_DISABLE_PROMPT ]]; then | |
prompt_segment blue black "(`basename $virtualenv_path`)" | |
fi | |
} | |
# Status: | |
# - was there an error | |
# - am I root | |
# - are there background jobs? | |
prompt_status() { | |
local symbols | |
symbols=() | |
[[ $RETVAL -ne 0 ]] && symbols+="%{%F{red}%}$CROSS" | |
[[ $UID -eq 0 ]] && symbols+="%{%F{yellow}%}$LIGHTNING" | |
[[ $(jobs -l | wc -l) -gt 0 ]] && symbols+="%{%F{cyan}%}$GEAR" | |
[[ -n "$symbols" ]] && prompt_segment $PRIMARY_FG default " $symbols " | |
} | |
# Setup for user input | |
# The manual break prevents background color from overflowing when the prompt is >1 line | |
# https://www.alexscotton.com/post/a-modular-responsive-zsh-theme-and-some-bonus-unix-commands | |
prompt_break() { | |
echo -n "\n" | |
} | |
prompt_cmd() { | |
echo -n '%# ' | |
} | |
## Main prompt | |
prompt_agnoster_main() { | |
RETVAL=$? | |
CURRENT_BG='NONE' | |
prompt_status | |
prompt_virtualenv | |
prompt_context | |
prompt_dir | |
prompt_git | |
prompt_end | |
prompt_break | |
prompt_cmd | |
} | |
PROMPT='%{%f%b%k%}$(prompt_agnoster_main)' |
# gitup: update multiple git repo remotes, then auto-pull if local is clean | |
# 1. array of paths to check | |
repos=( | |
#~/repos/repo1/ | |
#~/repos/repo2/ | |
#etc | |
) | |
# 2. git remote update | |
# Improved with http://stackoverflow.com/questions/5083224/git-pull-while-not-in-a-git-directory once git -v 1.8.5 is out | |
function gitup() { | |
local GIT_STATUS='' | |
POST_1_8_5_GIT=$(git_compare_version "1.8.5") | |
if [[ $POST_1_8_5_GIT -gt 0 ]]; then | |
for i in ${repos}; do | |
echo $'\n\U2605' $i | |
git --work-tree=$i --git-dir=$i.git remote -v update | |
dirty=$(parse_git_dirty) | |
if [[ "$dirty" = "$ZSH_THEME_GIT_PROMPT_DIRTY" ]]; then | |
git fetch -v --all | |
# add --all to show all branches rather than just current | |
git log --graph --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset' ..FETCH_HEAD | cat | |
echo $'\n' $i $'→ dirty' | |
elif [[ "$dirty" = "$ZSH_THEME_GIT_PROMPT_UNTRACKED" ]]; then | |
git fetch -v --all | |
# set merge to use upstream by default with: git config --add --global merge.defaultToUpstream true | |
git merge --ff-only | |
git log --graph --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset' ORIG_HEAD.. | cat | |
echo $'\n✔' | |
else | |
git fetch -v --all | |
# set merge to use upstream by default with: git config --add --global merge.defaultToUpstream true | |
git merge --ff-only | |
git log --graph --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset' ORIG_HEAD.. | cat | |
echo $'✔' | |
fi | |
else | |
# for pre-git 1.8.5. Moving back to $STARTING_DIR is unreliable | |
local STARTING_DIR=$(pwd) | |
for i in ${repos}; do | |
cd ${i} | |
echo $'\n\U2605' $i | |
dirty=$(parse_git_dirty) | |
if [[ "$dirty" = "$ZSH_THEME_GIT_PROMPT_DIRTY" ]]; then | |
git fetch -v --all | |
# add --all to show all branches rather than just current | |
git log --graph --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset' ..FETCH_HEAD | cat | |
echo $'\n' $i $'→ dirty' | |
elif [[ "$dirty" = "$ZSH_THEME_GIT_PROMPT_UNTRACKED" ]]; then | |
git fetch -v --all | |
# set merge to use upstream by default with: git config --add --global merge.defaultToUpstream true | |
git merge --ff-only | |
git log --graph --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset' ORIG_HEAD.. | cat | |
echo $'\n✔' | |
else | |
git fetch -v --all | |
# set merge to use upstream by default with: git config --add --global merge.defaultToUpstream true | |
git merge --ff-only | |
git log --graph --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset' ORIG_HEAD.. | cat | |
echo $'✔' | |
fi | |
done | |
cd $STARTING_DIR | |
} | |
# Git version checker from Oh My ZSH git.zsh | |
#compare the provided version of git to the version installed and on path | |
#prints 1 if input version <= installed version | |
#prints -1 otherwise | |
function git_compare_version() { | |
local INPUT_GIT_VERSION=$1; | |
local INSTALLED_GIT_VERSION | |
INPUT_GIT_VERSION=(${(s/./)INPUT_GIT_VERSION}); | |
INSTALLED_GIT_VERSION=($(command git --version 2>/dev/null)); | |
INSTALLED_GIT_VERSION=(${(s/./)INSTALLED_GIT_VERSION[3]}); | |
for i in {1..3}; do | |
if [[ $INSTALLED_GIT_VERSION[$i] -gt $INPUT_GIT_VERSION[$i] ]]; then | |
echo 1 | |
return 0 | |
fi | |
if [[ $INSTALLED_GIT_VERSION[$i] -lt $INPUT_GIT_VERSION[$i] ]]; then | |
echo -1 | |
return 0 | |
fi | |
done | |
echo 0 | |
} | |
#this is unlikely to change so make it all statically assigned | |
POST_1_8_5_GIT=$(git_compare_version "1.8.5") | |
#clean up the namespace slightly by removing the checker function | |
unset -f git_compare_version |
Nevermind -- I think it was the git plugin for oh-my-zsh that I was using. I compared the one I had on my previous install which I knew worked and overwrote the one I just installed oh-my-zsh and it's working like a charm.
Although I can't seem to get the BEHIND_REMOTE to work...any ideas?
Hey Jason,
It took me a while to get all this working, because I have little to no idea what’s going on here 🐱
git_remote_status
is a function in oh-my-zsh’s git.zsh lib.
I updated the gist with what I currently use (power up!), and I note I changed Line 16 from
if [[ "$remote" = "$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE" ]] && [[ -n $dirty ]]; then
to
if [[ "$remote" = "$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE" ]] && [[ "$dirty" = "$ZSH_THEME_GIT_PROMPT_DIRTY" ]]; then
which may affect the issue you’re having with $ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE
.
HTH!
Thanks for that! I added that power up but still not seeing anything different.
Maybe it's because I'm looking for something that may not be there. Here's what I'm thinking, if the repo has been updated on github (or whereever) and I cd into my local repo of it. As soon as my prompt appears, I would want it to indicate that the github repo has been changed.
Is that what this should be doing? Or is there something that I need to do to make the indicator show me there's an update?
Thanks again!
aah, you need to use git fetch
or run the command (gitup
) to get remote updates, otherwise the shell won’t have that info. I use gitup
to update a bunch of repos at once in the morning, then use git fetch
before pushing or when there are remote changes I want to get.
PS remember to set your repo paths before using gitup
(or whatever you want to name it)
Ah ok -- oh well -- I would've hoped that it did it for me :).
I guess what I'm looking for is some indication that there's been changes without me doing something first. Basically to stop me from going on with my coding and only to find out that the repo has been updated and I didn't merge that update prior to my code/commit.
You could write a function that did. It would need to take a value (a path), change to that directory, then run the command on that directory. Oh, hey, that might be useful for me too:
#1.4. git remote update for current directory (or cd to path given)
# todo: improve with http://stackoverflow.com/questions/5083224/git-pull-while-not-in-a-git-directory once git -v 1.8.5 is out
function gitup() {
if (( $# ))
then cd $@
fi
local GIT_STATUS1=''
local GIT_STATUS2=''
dirty=$(parse_git_dirty)
if [[ "$dirty" = "$ZSH_THEME_GIT_PROMPT_DIRTY" ]]; then
#git remote -v update
git fetch -v --all
# add --all to show all branches rather than just current
git log --graph --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset' ..FETCH_HEAD | cat
echo $'\n' $i $'→ dirty'
elif [[ "$dirty" = "$ZSH_THEME_GIT_PROMPT_UNTRACKED" ]]; then
git fetch -v --all
# set merge to use upstream by default with: git config --add --global merge.defaultToUpstream true
git merge --ff-only
git log --graph --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset' ORIG_HEAD.. | cat
echo $'\n✔'
else
git fetch -v --all
# set merge to use upstream by default with: git config --add --global merge.defaultToUpstream true
git merge --ff-only
git log --graph --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset' ORIG_HEAD.. | cat
echo $'✔'
fi
}
2014-12-02 Updated with my full Agnoster-based .zsh-theme
. Stuff of interest:
- https://gist.github.com/oli/7686885#file-agnoster-oli-zsh-theme-L79 Git prompt sugar
- https://gist.github.com/oli/7686885#file-agnoster-oli-zsh-theme-L146 Path trimming based on terminal width
- https://gist.github.com/oli/7686885#file-agnoster-oli-zsh-theme-L146 Prevent >1 line prompt from vomiting background color
I've been trying to get my prompt to work with this theme and tried your function here, but I'm getting the feeling I missed something during my install because for whatever reason, I always get a green background on the branch segment with no icons, no matter what the status if the repo is.
I've been trying various functions and came by yours and like what I can see from the code, but can't get it to work. I'm getting this error
prompt_git:9: command not found: git_remote_status
Any ideas?