2015-10-19 17:37:18 +02:00
# vim:ft=zsh ts=2 sw=2 sts=2 et fenc=utf-8
################################################################
2015-10-23 23:42:59 +02:00
# Utility functions
2015-10-19 17:37:18 +02:00
# This file holds some utility-functions for
# the powerlevel9k-ZSH-theme
# https://github.com/bhilburn/powerlevel9k
################################################################
# Exits with 0 if a variable has been previously defined (even if empty)
# Takes the name of a variable that should be checked.
function defined( ) {
2018-07-12 20:34:56 +02:00
[ [ ! -z " ${ (tP)1 } " ] ]
2015-10-19 17:37:18 +02:00
}
# Given the name of a variable and a default value, sets the variable
# value to the default only if it has not been defined.
#
# Typeset cannot set the value for an array, so this will only work
# for scalar values.
function set_default( ) {
local varname = " $1 "
local default_value = " $2 "
defined " $varname " || typeset -g " $varname " = " $default_value "
}
# Converts large memory values into a human-readable unit (e.g., bytes --> GB)
2016-02-09 22:44:45 +02:00
# Takes two arguments:
# * $size - The number which should be prettified
# * $base - The base of the number (default Bytes)
2015-10-19 17:37:18 +02:00
printSizeHumanReadable( ) {
2015-10-22 10:10:15 +02:00
typeset -F 2 size
size = " $1 " +0.00001
2015-10-19 17:37:18 +02:00
local extension
2015-10-22 10:10:15 +02:00
extension = ( 'B' 'K' 'M' 'G' 'T' 'P' 'E' 'Z' 'Y' )
2015-10-19 17:37:18 +02:00
local index = 1
# if the base is not Bytes
if [ [ -n $2 ] ] ; then
2018-03-27 01:09:41 +02:00
local idx
2015-10-19 17:37:18 +02:00
for idx in " ${ extension [@] } " ; do
if [ [ " $2 " = = " $idx " ] ] ; then
break
fi
index = $(( index + 1 ))
done
fi
2015-10-22 10:10:15 +02:00
while ( ( ( size / 1024) > 0.1 ) ) ; do
2015-10-19 17:37:18 +02:00
size = $(( size / 1024 ))
index = $(( index + 1 ))
done
echo " $size ${ extension [ $index ] } "
}
# Gets the first value out of a list of items that is not empty.
# The items are examined by a callback-function.
# Takes two arguments:
# * $list - A list of items
# * $callback - A callback function to examine if the item is
# worthy. The callback function has access to
# the inner variable $item.
function getRelevantItem( ) {
2016-01-22 20:11:33 +02:00
local -a list
local callback
# Explicitly split the elements by whitespace.
2016-02-06 21:07:42 +02:00
list = ( ${ =1 } )
2015-10-19 17:37:18 +02:00
callback = $2
for item in $list ; do
# The first non-empty item wins
try = $( eval " $callback " )
if [ [ -n " $try " ] ] ; then
echo " $try "
break;
fi
done
}
2017-04-18 23:59:39 +02:00
# OS detection
2015-10-19 17:37:18 +02:00
case $( uname) in
Darwin)
OS = 'OSX'
OS_ICON = $( print_icon 'APPLE_ICON' )
; ;
2018-06-30 17:20:02 +02:00
CYGWIN_NT-* | MSYS_NT-*)
2017-05-07 15:34:54 +02:00
OS = 'Windows'
OS_ICON = $( print_icon 'WINDOWS_ICON' )
; ;
2015-10-19 17:37:18 +02:00
FreeBSD)
OS = 'BSD'
OS_ICON = $( print_icon 'FREEBSD_ICON' )
; ;
OpenBSD)
OS = 'BSD'
OS_ICON = $( print_icon 'FREEBSD_ICON' )
; ;
DragonFly)
OS = 'BSD'
OS_ICON = $( print_icon 'FREEBSD_ICON' )
; ;
Linux)
2018-02-19 19:48:21 +02:00
OS = 'Linux'
2018-09-07 11:52:21 +02:00
if [ -f /etc/os-release ] ; then
2019-01-24 00:11:01 +02:00
[ [ ${ (f) " $(( </ etc/os-release) 2 >/dev/null) "} =~ " ID = ( [ A-Za-z] + ) " ]] && os_release_id=" ${ match [1] } "
2018-09-07 11:52:21 +02:00
fi
2018-02-16 17:45:09 +02:00
case " $os_release_id " in
2018-05-19 02:12:05 +02:00
*arch*)
2018-02-16 17:45:09 +02:00
OS_ICON = $( print_icon 'LINUX_ARCH_ICON' )
; ;
2018-05-19 02:12:05 +02:00
*debian*)
2018-02-16 13:56:47 +02:00
OS_ICON = $( print_icon 'LINUX_DEBIAN_ICON' )
2018-02-16 17:45:09 +02:00
; ;
2018-05-19 02:12:05 +02:00
*ubuntu*)
2018-02-16 17:45:09 +02:00
OS_ICON = $( print_icon 'LINUX_UBUNTU_ICON' )
; ;
2018-05-19 02:12:05 +02:00
*elementary*)
2018-02-16 17:45:09 +02:00
OS_ICON = $( print_icon 'LINUX_ELEMENTARY_ICON' )
; ;
2018-05-19 02:12:05 +02:00
*fedora*)
2018-02-16 17:45:09 +02:00
OS_ICON = $( print_icon 'LINUX_FEDORA_ICON' )
; ;
2018-05-19 02:12:05 +02:00
*coreos*)
2018-02-16 17:45:09 +02:00
OS_ICON = $( print_icon 'LINUX_COREOS_ICON' )
; ;
2018-05-19 02:12:05 +02:00
*gentoo*)
2018-02-16 17:45:09 +02:00
OS_ICON = $( print_icon 'LINUX_GENTOO_ICON' )
; ;
2018-05-19 02:12:05 +02:00
*mageia*)
2018-02-16 17:45:09 +02:00
OS_ICON = $( print_icon 'LINUX_MAGEIA_ICON' )
; ;
2018-05-19 02:12:05 +02:00
*centos*)
2018-02-16 17:45:09 +02:00
OS_ICON = $( print_icon 'LINUX_CENTOS_ICON' )
; ;
2018-05-19 02:12:05 +02:00
*opensuse*| *tumbleweed*)
2018-02-16 17:45:09 +02:00
OS_ICON = $( print_icon 'LINUX_OPENSUSE_ICON' )
; ;
2018-05-19 02:12:05 +02:00
*sabayon*)
2018-02-16 17:45:09 +02:00
OS_ICON = $( print_icon 'LINUX_SABAYON_ICON' )
; ;
2018-05-19 02:12:05 +02:00
*slackware*)
2018-02-16 17:45:09 +02:00
OS_ICON = $( print_icon 'LINUX_SLACKWARE_ICON' )
; ;
2018-05-19 02:12:05 +02:00
*linuxmint*)
2018-02-16 13:56:47 +02:00
OS_ICON = $( print_icon 'LINUX_MINT_ICON' )
2018-02-16 17:45:09 +02:00
; ;
2018-05-19 02:12:05 +02:00
*alpine*)
2018-03-20 19:31:46 +02:00
OS_ICON = $( print_icon 'LINUX_ALPINE_ICON' )
; ;
2018-05-19 02:12:05 +02:00
*aosc*)
2018-03-20 19:31:46 +02:00
OS_ICON = $( print_icon 'LINUX_AOSC_ICON' )
; ;
2018-05-19 02:12:05 +02:00
*nixos*)
2018-03-20 19:31:46 +02:00
OS_ICON = $( print_icon 'LINUX_NIXOS_ICON' )
; ;
2018-05-19 02:12:05 +02:00
*devuan*)
2018-03-20 19:31:46 +02:00
OS_ICON = $( print_icon 'LINUX_DEVUAN_ICON' )
; ;
2018-05-19 02:12:05 +02:00
*manjaro*)
2018-03-20 19:31:46 +02:00
OS_ICON = $( print_icon 'LINUX_MANJARO_ICON' )
; ;
2018-02-16 17:45:09 +02:00
*)
OS = 'Linux'
OS_ICON = $( print_icon 'LINUX_ICON' )
; ;
esac
2018-02-16 13:56:47 +02:00
2017-04-12 23:39:10 +02:00
# Check if we're running on Android
case $( uname -o 2>/dev/null) in
Android)
OS = 'Android'
OS_ICON = $( print_icon 'ANDROID_ICON' )
; ;
esac
2015-10-19 17:37:18 +02:00
; ;
SunOS)
OS = 'Solaris'
OS_ICON = $( print_icon 'SUNOS_ICON' )
; ;
*)
OS = ''
OS_ICON = ''
; ;
esac
# Determine the correct sed parameter.
#
# `sed` is unfortunately not consistent across OSes when it comes to flags.
SED_EXTENDED_REGEX_PARAMETER = "-r"
if [ [ " $OS " = = 'OSX' ] ] ; then
local IS_BSD_SED = " $( sed --version & >> /dev/null || echo "BSD sed" ) "
if [ [ -n " $IS_BSD_SED " ] ] ; then
SED_EXTENDED_REGEX_PARAMETER = "-E"
fi
fi
2015-11-17 02:39:49 +02:00
2016-08-11 21:40:05 +02:00
# Determine if the passed segment is used in the prompt
#
# Pass the name of the segment to this function to test for its presence in
# either the LEFT or RIGHT prompt arrays.
# * $1: The segment to be tested.
segment_in_use( ) {
local key = $1
if [ [ -n " ${ POWERLEVEL9K_LEFT_PROMPT_ELEMENTS [(r) $key ] } " ] ] || [ [ -n " ${ POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS [(r) $key ] } " ] ] ; then
return 0
else
return 1
fi
}
2015-11-17 02:39:49 +02:00
# Print a deprecation warning if an old segment is in use.
# Takes the name of an associative array that contains the
# deprecated segments as keys, the values contain the new
# segment names.
print_deprecation_warning( ) {
2015-11-17 19:34:18 +02:00
typeset -AH raw_deprecated_segments
raw_deprecated_segments = ( ${ (kvP@)1 } )
2015-11-17 02:39:49 +02:00
for key in ${ (@k)raw_deprecated_segments } ; do
2016-08-11 21:40:05 +02:00
if segment_in_use $key ; then
2015-11-17 02:39:49 +02:00
# segment is deprecated
print -P " %F{yellow}Warning!%f The ' $key ' segment is deprecated. Use '%F{blue} ${ raw_deprecated_segments [ $key ] } %f' instead. For more informations, have a look at the CHANGELOG.md. "
fi
done
}
2016-01-22 20:13:07 +02:00
# A helper function to determine if a segment should be
# joined or promoted to a full one.
# Takes three arguments:
# * $1: The array index of the current segment
# * $2: The array index of the last printed segment
# * $3: The array of segments of the left or right prompt
function segmentShouldBeJoined( ) {
local current_index = $1
local last_segment_index = $2
# Explicitly split the elements by whitespace.
local -a elements
2016-02-06 21:07:42 +02:00
elements = ( ${ =3 } )
2016-01-22 20:13:07 +02:00
local current_segment = ${ elements [ $current_index ] }
local joined = false
if [ [ ${ current_segment [-7,-1] } = = '_joined' ] ] ; then
joined = true
# promote segment to a full one, if the predecessing full segment
# was conditional. So this can only be the case for segments that
# are not our direct predecessor.
if ( ( $(( $current_index - $last_segment_index )) > 1) ) ; then
# Now we have to examine every previous segment, until we reach
# the last printed one (found by its index). This is relevant if
# all previous segments are joined. Then we want to join our
# segment as well.
local examined_index = $(( current_index - 1 ))
while ( ( $examined_index > $last_segment_index ) ) ; do
local previous_segment = ${ elements [ $examined_index ] }
# If one of the examined segments is not joined, then we know
# that the current segment should not be joined, as the target
# segment is the wrong one.
if [ [ ${ previous_segment [-7,-1] } != '_joined' ] ] ; then
joined = false
break
fi
examined_index = $(( examined_index - 1 ))
done
fi
fi
# Return 1 means error; return 0 means no error. So we have
# to invert $joined
if [ [ " $joined " = = "true" ] ] ; then
return 0
else
return 1
fi
}
2016-03-18 00:00:20 +02:00
2018-02-19 20:00:15 +02:00
################################################################
# Given a directory path, truncate it according to the settings.
# Parameters:
# * $1 Path: string - the directory path to be truncated
# * $2 Length: integer - length to truncate to
# * $3 Delimiter: string - the delimiter to use
# * $4 From: string - "right" | "middle". If omited, assumes right.
function truncatePath( ) {
# if the current path is not 1 character long (e.g. "/" or "~")
if ( ( ${# 1 } > 1 ) ) ; then
# convert $2 from string to integer
2 = $(( $2 ))
# set $3 to "" if not defined
2018-02-22 20:33:43 +02:00
[ [ -z $3 ] ] && 3 = "" || 3 = $( echo -n $3 )
2018-02-19 20:00:15 +02:00
# set $4 to "right" if not defined
[ [ -z $4 ] ] && 4 = "right"
# create a variable for the truncated path.
local trunc_path
2018-02-19 21:59:41 +02:00
# if the path is in the home folder, add "~/" to the start otherwise "/"
[ [ $1 = = "~" * ] ] && trunc_path = '~/' || trunc_path = '/'
2018-02-19 21:52:07 +02:00
# split the path into an array using "/" as the delimiter
2018-02-22 20:22:04 +02:00
local paths = $1
paths = ( ${ (s : / : ) ${ paths // "~\/" / } } )
2018-02-19 20:00:15 +02:00
# declare locals for the directory being tested and its length
2018-02-22 20:33:43 +02:00
local test_dir test_dir_length
2018-02-19 20:00:15 +02:00
# do the needed truncation
case $4 in
right)
# include the delimiter length in the threshhold
2018-02-22 20:33:43 +02:00
local threshhold = $(( $2 + ${# 3 } ))
2018-02-19 20:00:15 +02:00
# loop through the paths
for ( ( i = 1; i<${# paths } ; i++ ) ) ; do
# get the current directory value
test_dir = $paths [ $i ]
test_dir_length = ${# test_dir }
# only truncate if the resulting truncation will be shorter than
# the truncation + delimiter length and at least 3 characters
if ( ( $test_dir_length > $threshhold ) ) && ( ( $test_dir_length > 3 ) ) ; then
# use the first $2 characters and the delimiter
trunc_path += " ${ test_dir : 0 : $2 } $3 / "
else
# use the full path
trunc_path += " ${ test_dir } / "
fi
done
; ;
middle)
# we need double the length for start and end truncation + delimiter length
2018-02-22 20:17:26 +02:00
local threshhold = $(( $2 * 2 ))
2018-02-19 20:00:15 +02:00
# create a variable for the start of the end truncation
local last_pos
# loop through the paths
for ( ( i = 1; i<${# paths } ; i++ ) ) ; do
# get the current directory value
test_dir = $paths [ $i ]
test_dir_length = ${# test_dir }
# only truncate if the resulting truncation will be shorter than
# the truncation + delimiter length
2018-02-22 20:17:26 +02:00
if ( ( $test_dir_length > $threshhold ) ) ; then
2018-02-19 20:00:15 +02:00
# use the first $2 characters, the delimiter and the last $2 characters
last_pos = $(( $test_dir_length - $2 ))
trunc_path += " ${ test_dir : 0 : $2 } $3 ${ test_dir : $last_pos : $test_dir_length } / "
else
# use the full path
trunc_path += " ${ test_dir } / "
fi
done
; ;
esac
# return the truncated path + the current directory
echo $trunc_path ${ 1 : t }
else # current path is 1 character long (e.g. "/" or "~")
echo $1
fi
}
2016-03-18 00:00:20 +02:00
# Given a directory path, truncate it according to the settings for
# `truncate_from_right`
function truncatePathFromRight( ) {
2017-07-12 03:29:31 +02:00
local delim_len = ${# POWERLEVEL9K_SHORTEN_DELIMITER :- 1 }
2016-10-27 09:31:02 +02:00
echo $1 | sed $SED_EXTENDED_REGEX_PARAMETER \
" s@(([^/]{ $(( POWERLEVEL9K_SHORTEN_DIR_LENGTH)) })([^/]{ $delim_len }))[^/]+/@\2 $POWERLEVEL9K_SHORTEN_DELIMITER /@g "
2016-03-18 00:00:20 +02:00
}
2016-08-10 00:07:04 +02:00
# Search recursively in parent folders for given file.
function upsearch ( ) {
2016-08-10 21:31:58 +02:00
if [ [ " $PWD " = = " $HOME " || " $PWD " = = "/" ] ] ; then
echo " $PWD "
elif test -e " $1 " ; then
pushd .. > /dev/null
upsearch " $1 "
popd > /dev/null
2016-08-10 00:07:04 +02:00
echo " $PWD "
else
2016-08-10 21:31:58 +02:00
pushd .. > /dev/null
upsearch " $1 "
popd > /dev/null
2016-08-10 00:07:04 +02:00
fi
}
2019-02-03 20:20:14 +02:00
# Parse IP address from ifconfig on OSX and from IP on Linux
# Parameters:
# $1 - string The desired Interface
# $2 - string A root prefix for testing purposes
function p9k::parseIp( ) {
local desiredInterface = " ${ 1 } "
if [ [ -z " ${ desiredInterface } " ] ] ; then
desiredInterface = "^[^ ]+"
fi
local ROOT_PREFIX = " ${ 2 } "
if [ [ " $OS " = = "OSX" ] ] ; then
# Get a plain list of all interfaces
local rawInterfaces = " $( ${ ROOT_PREFIX } /sbin/ifconfig -l 2>/dev/null) "
# Parse into array (split by whitespace)
local -a interfaces
interfaces = ( ${ =rawInterfaces } )
# Parse only relevant interface names
local pattern = " ${ desiredInterface } [^ ]? "
local -a relevantInterfaces
for rawInterface in $interfaces ; do
[ [ " $rawInterface " = ~ $pattern ] ] && relevantInterfaces += ( $MATCH )
done
local newline = $'\n'
for interfaceName in $relevantInterfaces ; do
local interface = " $( ${ ROOT_PREFIX } /sbin/ifconfig $interfaceName 2>/dev/null) "
2019-02-06 09:53:46 +02:00
if [ [ " ${ interface } " = ~ "lo[0-9]*" ] ] ; then
continue
fi
2019-02-03 20:20:14 +02:00
# Check if interface is UP.
2019-02-06 09:53:46 +02:00
if [ [ " ${ interface / ${ newline } / } " = ~ "<UP(,)?[^>]*>(.*)inet[ ]+([^ ]*)" ] ] ; then
2019-02-03 20:20:14 +02:00
echo " ${ match [3] } "
return 0
fi
done
else
local -a interfaces
interfaces = ( " ${ (f) $( ${ ROOT_PREFIX } /sbin/ip -brief -4 a show 2>/dev/null) } " )
local pattern = " ^ ${ desiredInterface } [ ]+UP[ ]+([^/ ]+) "
for interface in " ${ (@)interfaces } " ; do
if [ [ " $interface " = ~ $pattern ] ] ; then
echo " ${ match [1] } "
return 0
fi
done
fi
return 1
}