lpr/liquidprompt
Olivier Mengué 9feb14caa5 Fix _lp_CPUNUM on Linux when 'nproc' is missing
On Linux, hide the "command not found" message on Linux when 'nproc'
is missing and the grep fallback is used.
(nproc doesn't exist on Debian Lenny, see issue #31 and #36)
2012-08-16 00:25:58 +02:00

1000 lines
30 KiB
Bash
Executable File

################################################################################
# LIQUID PROMPT
# An intelligent and non intrusive prompt for bash and zsh
################################################################################
# Licensed under the AGPL version 3
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
###########
# AUTHORS #
###########
# nojhan <nojhan@gmail.com> # Main author.
# Aurelien Requiem <aurelien@requiem.fr> # Major clean refactoring, variable path length, error codes, several bugfixes.
# Joris Dedieu <joris@pontiac3.nfrance.com> # Portability framework, FreeBSD support, bugfixes.
# Ludovic Rousseau <ludovic.rousseau@gmail.com> # Lot of bugfixes.
# Yann 'Ze' Richard <ze@nbox.org> # Do not fail on missing commands.
# François Schmidts <fschmidts@olfeo.com> # Simpler SSH_IP acquiring method.
# Thomas Debesse <thomas.debesse@gmail.com> # Fix columns use.
# Florian Le Frioux <florian@lefrioux.fr> # Use ± mark when root in VCS dir.
# Luc Didry <luc@fiat-tux.fr> # Zsh port
# Olivier Mengué <dolmen@cpan.org> # Major optimizations on host parsing
# See the README.md file for a summary of features.
# Check for recent enough version of bash.
if test -n "$BASH_VERSION" -a -n "$PS1" -a -n "$TERM" ; then
bash=${BASH_VERSION%.*}; bmajor=${bash%.*}; bminor=${bash#*.}
if [[ $bmajor -lt 3 ]] || [[ $bmajor -eq 3 && $bminor -lt 2 ]]; then
unset bash bmajor bminor
return
fi
unset bash bmajor bminor
_LP_WORKING_SHELL=bash
_LP_OPEN_ESC="\["
_LP_CLOSE_ESC="\]"
_LP_USER_SYMBOL="\u"
_LP_HOST_SYMBOL="\h"
elif test -n "$ZSH_VERSION" ; then
_LP_WORKING_SHELL=zsh
_LP_OPEN_ESC="%{"
_LP_CLOSE_ESC="%}"
_LP_USER_SYMBOL="%n"
_LP_HOST_SYMBOL="%m"
else
echo "liquidprompt: shell not supported" >&2
return
fi
###############
# OS specific #
###############
# LP_OS detection, default to Linux
case $(uname) in
FreeBSD) LP_OS=FreeBSD ;;
DragonFly) LP_OS=FreeBSD ;;
Darwin) LP_OS=FreeBSD ;;
SunOS) LP_OS=SunOS ;;
*) LP_OS=Linux ;;
esac
# Colors declarations
if [[ "$LP_OS" == "FreeBSD" ]] ; then
BOLD="${_LP_OPEN_ESC}$(tput md)${_LP_CLOSE_ESC}"
BLACK="${_LP_OPEN_ESC}$(tput AF 0)${_LP_CLOSE_ESC}"
BOLD_GRAY="${_LP_OPEN_ESC}$(tput md ; tput AF 0)${_LP_CLOSE_ESC}"
WHITE="${_LP_OPEN_ESC}$(tput AF 7)${_LP_CLOSE_ESC}"
BOLD_WHITE="${_LP_OPEN_ESC}$(tput md ; tput AF 7)${_LP_CLOSE_ESC}"
RED="${_LP_OPEN_ESC}$(tput AF 1)${_LP_CLOSE_ESC}"
BOLD_RED="${_LP_OPEN_ESC}$(tput md ; tput AF 1)${_LP_CLOSE_ESC}"
WARN_RED="${_LP_OPEN_ESC}$(tput AF 0 ; tput setab 1)${_LP_CLOSE_ESC}"
CRIT_RED="${_LP_OPEN_ESC}$(tput md; tput AF 7 ; tput setab 1)${_LP_CLOSE_ESC}"
DANGER_RED="${_LP_OPEN_ESC}$(tput md; tput AF 3 ; tput setab 1)${_LP_CLOSE_ESC}"
GREEN="${_LP_OPEN_ESC}$(tput AF 2)${_LP_CLOSE_ESC}"
BOLD_GREEN="${_LP_OPEN_ESC}$(tput md ; tput AF 2)${_LP_CLOSE_ESC}"
YELLOW="${_LP_OPEN_ESC}$(tput AF 3)${_LP_CLOSE_ESC}"
BOLD_YELLOW="${_LP_OPEN_ESC}$(tput md ; tput AF 3)${_LP_CLOSE_ESC}"
BLUE="${_LP_OPEN_ESC}$(tput AF 4)${_LP_CLOSE_ESC}"
BOLD_BLUE="${_LP_OPEN_ESC}$(tput md ; tput AF 4)${_LP_CLOSE_ESC}"
PURPLE="${_LP_OPEN_ESC}$(tput AF 5)${_LP_CLOSE_ESC}"
PINK="${_LP_OPEN_ESC}$(tput md ; tput AF 5)${_LP_CLOSE_ESC}"
CYAN="${_LP_OPEN_ESC}$(tput AF 6)${_LP_CLOSE_ESC}"
BOLD_CYAN="${_LP_OPEN_ESC}$(tput md ; tput AF 6)${_LP_CLOSE_ESC}"
NO_COL="${_LP_OPEN_ESC}$(tput me)${_LP_CLOSE_ESC}"
else
# default to Linux
BOLD="${_LP_OPEN_ESC}$(tput bold)${_LP_CLOSE_ESC}"
BLACK="${_LP_OPEN_ESC}$(tput setaf 0)${_LP_CLOSE_ESC}"
BOLD_GRAY="${_LP_OPEN_ESC}$(tput bold ; tput setaf 0)${_LP_CLOSE_ESC}"
WHITE="${_LP_OPEN_ESC}$(tput setaf 7)${_LP_CLOSE_ESC}"
BOLD_WHITE="${_LP_OPEN_ESC}$(tput bold ; tput setaf 7)${_LP_CLOSE_ESC}"
RED="${_LP_OPEN_ESC}$(tput setaf 1)${_LP_CLOSE_ESC}"
BOLD_RED="${_LP_OPEN_ESC}$(tput bold ; tput setaf 1)${_LP_CLOSE_ESC}"
WARN_RED="${_LP_OPEN_ESC}$(tput setaf 0 ; tput setab 1)${_LP_CLOSE_ESC}"
CRIT_RED="${_LP_OPEN_ESC}$(tput bold; tput setaf 7 ; tput setab 1)${_LP_CLOSE_ESC}"
DANGER_RED="${_LP_OPEN_ESC}$(tput bold; tput setaf 3 ; tput setab 1)${_LP_CLOSE_ESC}"
GREEN="${_LP_OPEN_ESC}$(tput setaf 2)${_LP_CLOSE_ESC}"
BOLD_GREEN="${_LP_OPEN_ESC}$(tput bold ; tput setaf 2)${_LP_CLOSE_ESC}"
YELLOW="${_LP_OPEN_ESC}$(tput setaf 3)${_LP_CLOSE_ESC}"
BOLD_YELLOW="${_LP_OPEN_ESC}$(tput bold ; tput setaf 3)${_LP_CLOSE_ESC}"
BLUE="${_LP_OPEN_ESC}$(tput setaf 4)${_LP_CLOSE_ESC}"
BOLD_BLUE="${_LP_OPEN_ESC}$(tput bold ; tput setaf 4)${_LP_CLOSE_ESC}"
PURPLE="${_LP_OPEN_ESC}$(tput setaf 5)${_LP_CLOSE_ESC}"
PINK="${_LP_OPEN_ESC}$(tput bold ; tput setaf 5)${_LP_CLOSE_ESC}"
CYAN="${_LP_OPEN_ESC}$(tput setaf 6)${_LP_CLOSE_ESC}"
BOLD_CYAN="${_LP_OPEN_ESC}$(tput bold ; tput setaf 6)${_LP_CLOSE_ESC}"
NO_COL="${_LP_OPEN_ESC}$(tput sgr0)${_LP_CLOSE_ESC}"
fi
# Get cpu count
case "$LP_OS" in
Linux) _lp_CPUNUM=$( nproc 2>/dev/null || grep -c '^[Pp]rocessor' /proc/cpuinfo ) ;;
FreeBSD) _lp_CPUNUM=$( sysctl -n hw.ncpu ) ;;
SunOS) _lp_CPUNUM=$( kstat -m cpu_info | grep -c "module: cpu_info" ) ;;
esac
# get current load
case "$LP_OS" in
Linux)
_lp_cpu_load () {
local load eol
read load eol < /proc/loadavg
echo "$load"
}
;;
FreeBSD)
_lp_cpu_load () {
local bol load eol
read bol load eol < $<( LANG=C sysctl -n vm.loadavg )
echo "$load"
}
;;
SunOS)
_lp_cpu_load () {
LANG=C uptime | awk '{print substr($10,0,length($10))}'
}
esac
#################
# CONFIGURATION #
#################
# Note: configuration is called _after_ colors declarations, because of themes.
# Default values
LP_BATTERY_THRESHOLD=${LP_BATTERY_THRESHOLD:-75}
LP_LOAD_THRESHOLD=${LP_LOAD_THRESHOLD:-60}
LP_PATH_LENGTH=${LP_PATH_LENGTH:-35}
LP_PATH_KEEP=${LP_PATH_KEEP:-2}
LP_HOSTNAME_ALWAYS=${LP_HOSTNAME_ALWAYS:-0}
LP_PS1=${LP_PS1:-""}
LP_BATTERY_MARK=${LP_BATTERY_MARK:-"⌁"}
LP_ADAPTER_MARK=${LP_ADAPTER_MARK:-"⏚"}
LP_LOAD_MARK=${LP_LOAD_MARK:-"⌂"}
LP_PROXY_MARK=${LP_PROXY_MARK:-"↥"}
LP_GIT_MARK=${LP_GIT_MARK:-"±"}
LP_MERCURIAL_MARK=${LP_MERCURIAL_MARK:-"☿"}
LP_SUBVERSION_MARK=${LP_SUBVERSION_MARK:-"‡"}
LP_COLOR_PATH=${LP_COLOR_PATH:-$BOLD_WHITE}
LP_COLOR_PATH_ROOT=${LP_COLOR_PATH_ROOT:-$BOLD_YELLOW}
LP_COLOR_PROXY=${LP_COLOR_PROXY:-$BOLD_BLUE}
LP_COLOR_JOB_D=${LP_COLOR_JOB_D:-$YELLOW}
LP_COLOR_JOB_R=${LP_COLOR_JOB_R:-$BOLD_YELLOW}
LP_COLOR_JOB_Z=${LP_COLOR_JOB_Z:-$BOLD_YELLOW}
LP_COLOR_ERR=${LP_COLOR_ERR:-$PURPLE}
LP_COLOR_MARK=${LP_COLOR_MARK:-$BOLD_WHITE}
LP_COLOR_MARK_ROOT=${LP_COLOR_MARK_ROOT:-$BOLD_RED}
LP_COLOR_USER_LOGGED=${LP_COLOR_USER_LOGGED:-""}
LP_COLOR_USER_ALT=${LP_COLOR_USER_ALT:-$BOLD}
LP_COLOR_USER_ROOT=${_ROOT:-$BOLD_YELLOW}
LP_COLOR_HOST=${LP_COLOR_HOST:-""}
LP_COLOR_SSH=${LP_COLOR_SSH:-$BOLD_CYAN}
LP_COLOR_TELNET=${LP_COLOR_TELNET:-$WARN_RED}
LP_COLOR_WRITE=${LP_COLOR_WRITE:-$GREEN}
LP_COLOR_NOWRITE=${LP_COLOR_NOWRITE:-$RED}
LP_COLOR_UP=${LP_COLOR_UP:-$GREEN}
LP_COLOR_COMMITS=${LP_COLOR_COMMITS:-$YELLOW}
LP_COLOR_CHANGES=${LP_COLOR_CHANGES:-$RED}
LP_COLOR_DIFF=${LP_COLOR_DIFF:-$PURPLE}
LP_COLOR_CHARGING_ABOVE=${LP_COLOR_CHARGING_ABOVE:-$GREEN}
LP_COLOR_CHARGING_UNDER=${LP_COLOR_CHARGING_UNDER:-$YELLOW}
LP_COLOR_DISCHARGING_ABOVE=${LP_COLOR_DISCHARGING_ABOVE:-$YELLOW}
LP_COLOR_DISCHARGING_UNDER=${LP_COLOR_DISCHARGING_UNDER:-$RED}
LP_COLORMAP_0=${LP_COLORMAP_0:-""}
LP_COLORMAP_1=${LP_COLORMAP_1:-$GREEN}
LP_COLORMAP_2=${LP_COLORMAP_2:-$BOLD_GREEN}
LP_COLORMAP_3=${LP_COLORMAP_3:-$YELLOW}
LP_COLORMAP_4=${LP_COLORMAP_4:-$BOLD_YELLOW}
LP_COLORMAP_5=${LP_COLORMAP_5:-$RED}
LP_COLORMAP_6=${LP_COLORMAP_6:-$BOLD_RED}
LP_COLORMAP_7=${LP_COLORMAP_7:-$WARN_RED}
LP_COLORMAP_8=${LP_COLORMAP_8:-$CRIT_RED}
LP_COLORMAP_9=${LP_COLORMAP_9:-$DANGER_RED}
# Default config file may be the XDG standard ~/.config/liquidpromptrc,
# but heirloom dotfile has priority.
_lp_source_config()
{
local configfile
if [[ -f "/etc/liquidpromptrc" ]]
then
source "/etc/liquidpromptrc"
fi
if [[ -f "$HOME/.liquidpromptrc" ]]
then
configfile="$HOME/.liquidpromptrc"
elif [[ -z "$XDG_HOME_DIR" ]]
then
configfile="$HOME/.config/liquidpromptrc"
else
configfile="$XDG_HOME_DIR/liquidpromptrc"
fi
if [[ -f "$configfile" ]]
then
source "$configfile"
fi
}
# do source config files
_lp_source_config
###############
# Who are we? #
###############
# Yellow for root, bold if the user is not the login one, else no color.
_lp_user()
{
local user
# if user is not root
if [[ "$EUID" -ne "0" ]] ; then
# if user is not login user
if [[ ${USER} != "$(logname 2>/dev/null)" ]]; then
user="${LP_COLOR_USER_ALT}${_LP_USER_SYMBOL}${NO_COL}"
else
user="${LP_COLOR_USER_LOGGED}${_LP_USER_SYMBOL}${NO_COL}"
fi
else
user="${LP_COLOR_USER_ROOT}${_LP_USER_SYMBOL}${NO_COL}"
fi
echo -ne $user
}
#################
# Where are we? #
#################
_lp_connection()
{
if [[ -n "$SSH_CLIENT$SSH2_CLIENT" ]] ; then
echo ssh
else
# TODO check on *BSD
local sess_src=$(who am i | sed -n 's/.*(\(.*\))/\1/p')
if [[ -z "$sess_src" || "$sess_src" = :0.0 || "$sess_src" == :0 ]] ; then
echo lcl # Local
else
echo tel # Telnet
fi
fi
}
# Put the hostname if not locally connected
# color it in cyan within SSH, and a warning red if within telnet
# else diplay the host without color
# The connection is not expected to change from inside the shell, so we
# build this just once
case "$(_lp_connection)" in
lcl)
if [[ $LP_HOSTNAME_ALWAYS == 0 ]] ; then
LP_HOST="${NO_COL}" # no hostname if local
else
LP_HOST="${NO_COL}@${LP_COLOR_HOST}${_LP_HOST_SYMBOL}${NO_COL}"
fi
;;
ssh)
LP_HOST="${NO_COL}@${LP_COLOR_SSH}${_LP_HOST_SYMBOL}${NO_COL}"
;;
tel)
LP_HOST="${NO_COL}@${LP_COLOR_TELNET}${_LP_HOST_SYMBOL}${NO_COL}"
;;
*)
LP_HOST="${NO_COL}@${_LP_HOST_SYMBOL}" # defaults to no color
;;
esac
# Useless now, so undefine
unset _lp_connection
# put an arrow if an http proxy is set
_lp_proxy()
{
if [[ ! -z "$http_proxy" ]] ; then
echo -ne $LP_PROXY_MARK
fi
}
# BASH/ZSH function that shortens
# a very long path for display by removing
# the left most parts and replacing them
# with a leading ...
#
# the first argument is the path
#
# the second argument is the maximum allowed
# length including the '/'s and ...
# http://hbfs.wordpress.com/2009/09/01/short-pwd-in-bash-prompts/
#
# + keep some left part of the path if asked
_lp_shorten_path()
{
# the character that will replace the part of the path that is masked
local mask=" … "
# index of the directory to keep from the root (starts at 0 whith bash, 1 with zsh)
local keep=$((LP_PATH_KEEP-1))
if [[ "$_LP_WORKING_SHELL" == "zsh" ]]; then
keep=$LP_PATH_KEEP
fi
local len_percent=$2
local p=$(echo "$1" | sed -e "s|$HOME|~|")
local len="${#p}"
local max_len=$((${COLUMNS:-80}*$len_percent/100))
local mask_len="${#mask}"
local slashes=0
if [[ "$_LP_WORKING_SHELL" == "bash" ]]; then
if [[ "$len" -gt "$max_len" ]]
then
# finds all the '/' in
# the path and stores their
# positions
#
local pos=()
for ((i=0;i<len;i++))
do
if [[ "${p:i:1}" == "/" ]]
then
pos=(${pos[@]} $i)
slashes=$((${slashes}+1))
fi
done
pos=(${pos[@]} $len)
# we have the '/'s, let's find the
# left-most that doesn't break the
# length limit
#
local i=$keep
if [[ $keep > $slashes ]] ; then
i=$slashes
fi
while [[ "$((len-pos[i]))" -gt "$((max_len-mask_len))" ]]
do
i=$((i+1))
done
# let us check if it's OK to
# print the whole thing
#
if [[ "${pos[i]}" -eq "0" ]]
then
# the path is shorter than
# the maximum allowed length,
# so no need for ...
#
echo "$p"
elif [[ "${pos[i]}" = "$len" ]]
then
# constraints are broken because
# the maximum allowed size is smaller
# than the last part of the path, plus
# ' … '
#
echo "${p:0:((${pos[${keep}]}+1))}${mask}${p:((len-max_len+mask_len))}"
else
# constraints are satisfied, at least
# some parts of the path, plus ' … ', are
# shorter than the maximum allowed size
#
echo "${p:0:((${pos[${keep}]}+1))}${mask}${p:pos[i]}"
fi
else
echo "$p"
fi
elif [[ "$_LP_WORKING_SHELL" == "zsh" ]]; then
if [[ "$len" -gt "$max_len" ]]; then
echo "%-${keep}~%${max_len}<${mask}<%~%<<"
else
echo "%~"
fi
fi
}
# Display a ":"
# colored in green if user have write permission on the current directory
# colored in red if it have not.
_lp_permissions_color()
{
if [[ -w "${PWD}" ]]; then
echo "${LP_COLOR_WRITE}:${NO_COL}"
else
echo "${LP_COLOR_NOWRITE}:${NO_COL}"
fi
}
################
# Related jobs #
################
# Either attached running jobs (started with $ myjob &)
# or attached stopped jobs (suspended with Ctrl-Z)
# or detached screens sessions running on the host
_lp_jobcount_color()
{
local running=$(( $(jobs -r | wc -l) ))
local stopped=$(( $(jobs -s | wc -l) ))
local screens=$(screen -ls 2> /dev/null | grep -c Detach )
local m_detached="d"
local m_stop="z"
local m_run="&"
local rep
# d/&/z
if [[ $screens != "0" && $running != "0" && $stopped != "0" ]] ; then
rep="${NO_COL}${LP_COLOR_JOB_D}${screens}${m_detached}${NO_COL}/${LP_COLOR_JOB_R}${running}${m_run}${NO_COL}/${LP_COLOR_JOB_Z}${stopped}${m_stop}${NO_COL}"
# _/&/_
elif [[ $screens == "0" && $running != "0" && $stopped == "0" ]] ; then
rep="${NO_COL}${LP_COLOR_JOB_R}${running}${m_run}${NO_COL}"
# _/_/z
elif [[ $screens == "0" && $running == "0" && $stopped != "0" ]] ; then
rep="${NO_COL}${LP_COLOR_JOB_Z}${stopped}${m_stop}${NO_COL}"
# d/_/_
elif [[ $screens != "0" && $running == "0" && $stopped == "0" ]] ; then
rep="${NO_COL}${LP_COLOR_JOB_D}${screens}${m_detached}${NO_COL}"
# d/&/_
elif [[ $screens != "0" && $running != "0" && $stopped == "0" ]] ; then
rep="${NO_COL}${LP_COLOR_JOB_D}${screens}${m_detached}${NO_COL}/${LP_COLOR_JOB_R}${running}${m_run}${NO_COL}"
# d/_/z
elif [[ $screens != "0" && $running == "0" && $stopped != "0" ]] ; then
rep="${NO_COL}${LP_COLOR_JOB_D}${screens}${m_detached}${NO_COL}/${LP_COLOR_JOB_Z}${stopped}${m_stop}${NO_COL}"
# _/&/z
elif [[ $screens == "0" && $running != "0" && $stopped != "0" ]] ; then
rep="${NO_COL}${LP_COLOR_JOB_R}${running}${m_run}${NO_COL}/${LP_COLOR_JOB_Z}${stopped}${m_stop}${NO_COL}"
fi
echo -ne "$rep"
}
# Display the return value of the last command, if different from zero
_lp_return_value()
{
if [[ "$1" -ne "0" ]]
then
echo -ne "$1"
fi
}
######################
# VCS branch display #
######################
# GIT #
# Get the branch name of the current directory
_lp_git_branch()
{
if git rev-parse --git-dir >/dev/null 2>&1 && [[ ! -z "$(git branch)" ]] ; then
echo -n "$(git branch 2>/dev/null | sed -n '/^\*/s/^\* //p;')"
fi
}
# Set a color depending on the branch state:
# - green if the repository is up to date
# - yellow if there is some commits not pushed
# - red if there is changes to commit
#
# Add the number of pending commits and the impacted lines.
_lp_git_branch_color()
{
command -v git >/dev/null 2>&1 || return 1;
local branch
branch=$(_lp_git_branch)
if [[ ! -z "$branch" ]] ; then
local GD
git diff --quiet >/dev/null 2>&1
GD=$?
local GDC
git diff --cached --quiet >/dev/null 2>&1
GDC=$?
local has_commit
has_commit=$(git rev-list --no-merges --count origin/${branch}..${branch} 2>/dev/null)
if [[ -z "$has_commit" ]] ; then
has_commit=0
fi
if [[ "$GD" -eq 1 || "$GDC" -eq "1" ]] ; then
local has_line
has_lines=$(git diff --numstat | awk 'NF==3 {plus+=$1; minus+=$2} END {printf("+%d/-%d\n", plus, minus)}')
if [[ "$has_commit" -gt "0" ]] ; then
# Changes to commit and commits to push
ret="${LP_COLOR_CHANGES}${branch}${NO_COL}(${LP_COLOR_DIFF}$has_lines${NO_COL},${LP_COLOR_COMMITS}$has_commit${NO_COL})"
else
ret="${LP_COLOR_CHANGES}${branch}${NO_COL}(${LP_COLOR_DIFF}$has_lines${NO_COL})" # changes to commit
fi
else
if [[ "$has_commit" -gt "0" ]] ; then
# some commit(s) to push
ret="${LP_COLOR_COMMITS}${branch}${NO_COL}(${LP_COLOR_COMMITS}$has_commit${NO_COL})"
else
ret="${LP_COLOR_UP}${branch}${NO_COL}" # nothing to commit or push
fi
fi
echo -ne "$ret"
fi
}
# MERCURIAL #
# Get the branch name of the current directory
_lp_hg_branch()
{
local branch
branch="$(hg branch 2>/dev/null)"
if [[ $? -eq 0 ]] && [[ ! -z "$(hg branch)" ]] ; then
echo -n "$(hg branch)"
fi
}
# Set a color depending on the branch state:
# - green if the repository is up to date
# - red if there is changes to commit
# - TODO: yellow if there is some commits not pushed
_lp_hg_branch_color()
{
command -v hg >/dev/null 2>&1 || return 1;
local branch
local ret
branch=$(_lp_hg_branch)
if [[ ! -z "$branch" ]] ; then
if [[ $(( $(hg status --quiet -n | wc -l) )) = 0 ]] ; then
ret="${LP_COLOR_UP}${branch}${NO_COL}"
else
ret="${LP_COLOR_CHANGES}${branch}${NO_COL}" # changes to commit
fi
echo -ne "$ret"
fi
}
# SUBVERSION #
# Get the branch name of the current directory
# For the first level of the repository, gives the repository name
_lp_svn_branch()
{
local infos
local ret
infos=$(svn info --xml 2>/dev/null)
ret=$?
if [[ $ret -eq 0 ]] ; then
local root
root=$(echo "$infos" | awk -v FS=">|</" '/^<root>/ { print $2 }')
local subrep
subrep=$(echo "$infos" | awk -v FS=">|</" '/^<url>/ { print $2 }')
if [[ "$subrep" == *"url>"* ]] ; then
echo -n $root
else
local branch
branch=$(basename $subrep)
echo -n $branch
fi
fi
}
# Set a color depending on the branch state:
# - green if the repository is up to date
# - red if there is changes to commit
# Note that, due to subversion way of managing changes,
# informations are only displayed for the CURRENT directory.
_lp_svn_branch_color()
{
command -v svn >/dev/null 2>&1 || return 1;
local branch
branch=$(_lp_svn_branch)
if [[ ! -z "$branch" ]] ; then
local commits
commits=$(( $(svn status | grep -v "?" -c) ))
if [[ $commits = 0 ]] ; then
local ret
ret="${LP_COLOR_UP}${branch}${NO_COL}"
else
ret="${LP_COLOR_CHANGES}${branch}${NO_COL}(${LP_COLOR_COMMITS}$commits${NO_COL})" # changes to commit
fi
echo -ne "$ret"
fi
}
##################
# Battery status #
##################
# Get the battery status in percent
# returns 0 (and battery level) if battery is discharging and under threshold
# returns 1 (and battery level) if battery is discharging and above threshold
# returns 2 (and battery level) if battery is charging but under threshold
# returns 3 (and battery level) if battery is charging and above threshold
# returns 4 if no battery support
_lp_battery()
{
command -v acpi >/dev/null 2>&1 || return 4; # or no battery support
local acpi
acpi="$(acpi --battery 2>/dev/null)"
local bat
bat=$( echo $acpi | sed "s/^Battery .*, \([0-9]*\)%.*$/\1/")
if [[ -z "${bat}" ]] ; then
# not battery level found
return 4
# discharging
elif [[ "$acpi" == *"Discharging"* ]] ; then
if [[ ${bat} -le $LP_BATTERY_THRESHOLD ]] ; then
# under threshold
echo -n "${bat}"
return 0
else
# above threshold
echo -n "${bat}"
return 1
fi
# charging
else
if [[ ${bat} -le $LP_BATTERY_THRESHOLD ]] ; then
# under threshold
echo -n "${bat}"
return 2
else
# above threshold
echo -n "${bat}"
return 3
fi
fi
}
# Compute a gradient of background/foreground colors depending on the battery status
# Display:
# a green ⏚ if the battery is charging and above threshold
# a yellow ⏚ if the battery is charging and under threshold
# a yellow ⌁ if the battery is discharging but above threshold
# a red ⌁ if the battery is discharging and above threshold
_lp_battery_color()
{
local mark=$LP_BATTERY_MARK
local chargingmark=$LP_ADAPTER_MARK
local bat
local ret
bat=$(_lp_battery)
ret=$?
if [[ $ret == 4 || $bat == 100 ]] ; then
# no battery support or battery full: nothing displayed
return
elif [[ $ret == 3 && $bat != 100 ]] ; then
# charging and above threshold and not 100%
# green ⏚
echo -ne "${LP_COLOR_CHARGING_ABOVE}$chargingmark${NO_COL}"
return
elif [[ $ret == 2 ]] ; then
# charging but under threshold
# yellow ⏚
echo -ne "${LP_COLOR_CHARGING_UNDER}$chargingmark${NO_COL}"
return
elif [[ $ret == 1 ]] ; then
# discharging but above threshold
# yellow ⌁
echo -ne "${LP_COLOR_DISCHARGING_ABOVE}$mark${NO_COL}"
return
# discharging and under threshold
elif [[ "$bat" != "" ]] ; then
local ret
ret="${LP_COLOR_DISCHARGING_UNDER}${mark}${NO_COL}"
if [[ ${bat} -le 100 ]] && [[ ${bat} -gt 80 ]] ; then # -20
ret="${ret}${LP_COLORMAP_1}"
elif [[ ${bat} -le 80 ]] && [[ ${bat} -gt 65 ]] ; then # -15
ret="${ret}${LP_COLORMAP_2}"
elif [[ ${bat} -le 65 ]] && [[ ${bat} -gt 50 ]] ; then # -15
ret="${ret}${LP_COLORMAP_3}"
elif [[ ${bat} -le 50 ]] && [[ ${bat} -gt 40 ]] ; then # -10
ret="${ret}${LP_COLORMAP_4}"
elif [[ ${bat} -le 40 ]] && [[ ${bat} -gt 30 ]] ; then # …
ret="${ret}${LP_COLORMAP_5}"
elif [[ ${bat} -le 30 ]] && [[ ${bat} -gt 20 ]] ; then
ret="${ret}${LP_COLORMAP_6}"
elif [[ ${bat} -le 20 ]] && [[ ${bat} -gt 10 ]] ; then
ret="${ret}${LP_COLORMAP_7}"
elif [[ ${bat} -le 10 ]] && [[ ${bat} -gt 5 ]] ; then
ret="${ret}${LP_COLORMAP_8}"
elif [[ ${bat} -le 5 ]] && [[ ${bat} -gt 0 ]] ; then
ret="${ret}${LP_COLORMAP_9}"
else
# for debugging purpose
ret="${ret}${LP_COLORMAP_0}"
fi
if [[ "$_LP_WORKING_SHELL" == "bash" ]]; then
echo -ne "${ret}${bat}%${NO_COL}"
elif [[ "$_LP_WORKING_SHELL" == "zsh" ]]; then
echo -ne "${ret}${bat}%%${NO_COL}"
fi
fi
}
###############
# System load #
###############
# Compute a gradient of background/forground colors depending on the battery status
_lp_load_color()
{
# Colour progression is important ...
# bold gray -> bold green -> bold yellow -> bold red ->
# black on red -> bold white on red
#
# Then we have to choose the values at which the colours switch, with
# anything past yellow being pretty important.
local load
load="$(_lp_cpu_load | sed 's/\.//g;s/^0*//g' )"
let "load=${load:-0}/$_lp_CPUNUM"
if [[ $load -ge $LP_LOAD_THRESHOLD ]]
then
local ret
ret="${LP_LOAD_MARK}${NO_COL}"
if [[ $load -ge 0 ]] && [[ $load -lt 20 ]] ; then
ret="${ret}${LP_COLORMAP_0}"
elif [[ $load -ge 20 ]] && [[ $load -lt 40 ]] ; then
ret="${ret}${LP_COLORMAP_1}"
elif [[ $load -ge 40 ]] && [[ $load -lt 60 ]] ; then
ret="${ret}${LP_COLORMAP_2}"
elif [[ $load -ge 60 ]] && [[ $load -lt 80 ]] ; then
ret="${ret}${LP_COLORMAP_3}"
elif [[ $load -ge 80 ]] && [[ $load -lt 100 ]] ; then
ret="${ret}${LP_COLORMAP_4}"
elif [[ $load -ge 100 ]] && [[ $load -lt 120 ]] ; then
ret="${ret}${LP_COLORMAP_5}"
elif [[ $load -ge 120 ]] && [[ $load -lt 140 ]] ; then
ret="${ret}${LP_COLORMAP_6}"
elif [[ $load -ge 140 ]] && [[ $load -lt 160 ]] ; then
ret="${ret}${LP_COLORMAP_7}"
elif [[ $load -ge 160 ]] && [[ $load -lt 180 ]] ; then
ret="${ret}${LP_COLORMAP_8}"
elif [[ $load -ge 180 ]] ; then
ret="${ret}${LP_COLORMAP_9}"
else
ret="${ret}${LP_COLORMAP_0}"
fi
if [[ "$_LP_WORKING_SHELL" == "bash" ]]; then
ret="${ret}$load%${NO_COL}"
elif [[ "$_LP_WORKING_SHELL" == "zsh" ]]; then
ret="${ret}$load%%${NO_COL}"
fi
echo -ne "${ret}"
fi
}
##########
# DESIGN #
##########
# Set the prompt mark to ± if git, to ☿ if mercurial, to ‡ if subversion
# to # if root and else $
_lp_smart_mark()
{
local COL
COL=${LP_COLOR_MARK}
if [[ "$EUID" -eq "0" ]] ; then
COL=${LP_COLOR_MARK_ROOT}
fi
local mark
mark="\$"
if [[ "$_LP_WORKING_SHELL" == "zsh" ]]; then
mark="%(!.#.$)"
fi
if [[ ! -z $(_lp_git_branch) ]] ; then
mark=$LP_GIT_MARK
elif [[ ! -z $(_lp_hg_branch) ]] ; then
mark=$LP_MERCURIAL_MARK
elif [[ ! -z $(_lp_svn_branch) ]] ; then
mark=$LP_SUBVERSION_MARK
fi
echo -ne "${COL}${mark}${NO_COL}"
}
# insert a space on the right
_lp_sr()
{
if [[ ! -z "$1" ]] ; then
echo -n "$1 "
fi
}
# insert a space on the left
_lp_sl()
{
if [[ ! -z "$1" ]] ; then
echo -n " $1"
fi
}
# insert two space, before and after
_lp_sb()
{
if [[ ! -z "$1" ]] ; then
echo -n " $1 "
fi
}
########################
# Construct the prompt #
########################
_lp_set_bash_prompt()
{
# as this get the last returned code, it should be called first
LP_ERR=$(_lp_sl "$(_lp_return_value $?)")
# execute the old prompt
$LP_OLD_PROMPT_COMMAND
# left of main prompt: space at right
LP_JOBS=$(_lp_sr "$(_lp_jobcount_color)")
LP_LOAD=$(_lp_sr "$(_lp_load_color)")
LP_BATT=$(_lp_sr "$(_lp_battery_color)")
# in main prompt: no space
LP_USER=$(_lp_user)
# LP_HOST is a global set at load time
LP_PERM=$(_lp_permissions_color)
LP_PWD=$(_lp_shorten_path "$PWD" $LP_PATH_LENGTH)
LP_PROXY=$(_lp_proxy)
# right of main prompt: space at left
LP_GIT=$(_lp_sl "$(_lp_git_branch_color)")
LP_HG=$(_lp_sl "$(_lp_hg_branch_color)")
LP_SVN=$(_lp_sl "$(_lp_svn_branch_color)")
# end of the prompt line: double spaces
LP_MARK=$(_lp_sb "$(_lp_smart_mark)")
if [[ -z $LP_PS1 ]] ; then
# add jobs, load and battery
PS1="${LP_BATT}${LP_LOAD}${LP_JOBS}"
# add user, host and permissions colon
PS1="${PS1}[${LP_USER}${LP_HOST}${LP_PERM}"
# if not root
if [[ "$EUID" -ne "0" ]]
then
# path in foreground color
PS1="${PS1}${LP_COLOR_PATH}${LP_PWD}${NO_COL}]${LP_COLOR_PROXY}${LP_PROXY}${NO_COL}"
# add VCS infos
PS1="${PS1}${LP_GIT}${LP_HG}${LP_SVN}"
else
# path in yellow
PS1="${PS1}${LP_PATH_ROOT}${LP_PWD}${NO_COL}]${LP_COLOR_PROXY}${LP_PROXY}${NO_COL}"
# do not add VCS infos
fi
# add return code and prompt mark
PS1="${PS1}${LP_COLOR_ERR}${LP_ERR}${NO_COL}${LP_MARK}"
# Glue the bash prompt always go to the first column.
# Avoid glitches after interrupting a command with Ctrl-C
# Does not seem to be necessary anymore?
#PS1="\[\033[G\]${PS1}${NO_COL}"
else
PS1=$LP_PS1
fi
}
# Activate the liquid prompt
prompt_on()
{
# if liquidprompt has not been already set
if [[ -z "$LP_LIQUIDPROMPT" ]] ; then
LP_OLD_PS1="$PS1"
if [[ "$_LP_WORKING_SHELL" == "bash" ]]; then
LP_OLD_PROMPT_COMMAND="$PROMPT_COMMAND"
elif [[ "$_LP_WORKING_SHELL" == "zsh" ]]; then
LP_OLD_PROMPT_COMMAND="$precmd"
fi
fi
if [[ "$_LP_WORKING_SHELL" == "bash" ]]; then
PROMPT_COMMAND=_lp_set_bash_prompt
elif [[ "$_LP_WORKING_SHELL" == "zsh" ]]; then
function precmd {
_lp_set_bash_prompt
}
fi
# Keep in mind that LP has been sourced
# (to avoid recursive prompt command).
LP_LIQUIDPROMPT=1
}
# Come back to the old prompt
prompt_off()
{
PS1=$LP_OLD_PS1
if [[ "$_LP_WORKING_SHELL" == "bash" ]]; then
PROMPT_COMMAND=$LP_OLD_PROMPT_COMMAND
elif [[ "$_LP_WORKING_SHELL" == "zsh" ]]; then
precmd=$LP_OLD_PROMPT_COMMAND
fi
}
# Use an empty prompt: just the \$ mark
prompt_OFF()
{
PS1="\$ "
if [[ "$_LP_WORKING_SHELL" == "bash" ]]; then
PROMPT_COMMAND=$LP_OLD_PROMPT_COMMAND
elif [[ "$_LP_WORKING_SHELL" == "zsh" ]]; then
precmd=$LP_OLD_PROMPT_COMMAND
fi
}
# By default, sourcing liquidprompt.bash will activate the liquid prompt
prompt_on
# Cleaning of variable that are not needed at runtime
unset LP_OS
# vim: set et sts=4 sw=4 tw=120 ft=sh: