|
- #!/bin/sh
- #
- # pfetch - Simple POSIX sh fetch script.
-
- # Wrapper around all escape sequences used by pfetch to allow for
- # greater control over which sequences are used (if any at all).
- esc() {
- case $1 in
- CUU) e="${esc_c}[${2}A" ;; # cursor up
- CUD) e="${esc_c}[${2}B" ;; # cursor down
- CUF) e="${esc_c}[${2}C" ;; # cursor right
- CUB) e="${esc_c}[${2}D" ;; # cursor left
-
- # text formatting
- SGR)
- case ${PF_COLOR:=1} in
- (1)
- e="${esc_c}[${2}m"
- ;;
-
- (0)
- # colors disabled
- e=
- ;;
- esac
- ;;
-
- # line wrap
- DECAWM)
- case $TERM in
- (dumb | minix | cons25)
- # not supported
- e=
- ;;
-
- (*)
- e="${esc_c}[?7${2}"
- ;;
- esac
- ;;
- esac
- }
-
- # Print a sequence to the terminal.
- esc_p() {
- esc "$@"
- printf '%s' "$e"
- }
-
- # This is just a simple wrapper around 'command -v' to avoid
- # spamming '>/dev/null' throughout this function. This also guards
- # against aliases and functions.
- has() {
- _cmd=$(command -v "$1") 2>/dev/null || return 1
- [ -x "$_cmd" ] || return 1
- }
-
- log() {
- # The 'log()' function handles the printing of information.
- # In 'pfetch' (and 'neofetch'!) the printing of the ascii art and info
- # happen independently of each other.
- #
- # The size of the ascii art is stored and the ascii is printed first.
- # Once the ascii is printed, the cursor is located right below the art
- # (See marker $[1]).
- #
- # Using the stored ascii size, the cursor is then moved to marker $[2].
- # This is simply a cursor up escape sequence using the "height" of the
- # ascii art.
- #
- # 'log()' then moves the cursor to the right the "width" of the ascii art
- # with an additional amount of padding to add a gap between the art and
- # the information (See marker $[3]).
- #
- # When 'log()' has executed, the cursor is then located at marker $[4].
- # When 'log()' is run a second time, the next line of information is
- # printed, moving the cursor to marker $[5].
- #
- # Markers $[4] and $[5] repeat all the way down through the ascii art
- # until there is no more information left to print.
- #
- # Every time 'log()' is called the script keeps track of how many lines
- # were printed. When printing is complete the cursor is then manually
- # placed below the information and the art according to the "heights"
- # of both.
- #
- # The math is simple: move cursor down $((ascii_height - info_height)).
- # If the aim is to move the cursor from marker $[5] to marker $[6],
- # plus the ascii height is 8 while the info height is 2 it'd be a move
- # of 6 lines downwards.
- #
- # However, if the information printed is "taller" (takes up more lines)
- # than the ascii art, the cursor isn't moved at all!
- #
- # Once the cursor is at marker $[6], the script exits. This is the gist
- # of how this "dynamic" printing and layout works.
- #
- # This method allows ascii art to be stored without markers for info
- # and it allows for easy swapping of info order and amount.
- #
- # $[2] ___ $[3] goldie@KISS
- # $[4](.· | $[5] os KISS Linux
- # (<> |
- # / __ \
- # ( / \ /|
- # _/\ __)/_)
- # \/-____\/
- # $[1]
- #
- # $[6] /home/goldie $
-
- # End here if no data was found.
- [ "$2" ] || return
-
- # Store the value of '$1' as we reset the argument list below.
- name=$1
-
- # Use 'set --' as a means of stripping all leading and trailing
- # white-space from the info string. This also normalizes all
- # white-space inside of the string.
- #
- # Disable the shellcheck warning for word-splitting
- # as it's safe and intended ('set -f' disables globbing).
- # shellcheck disable=2046,2086
- {
- set -f
- set +f -- $2
- info=$*
- }
-
- # Move the cursor to the right, the width of the ascii art with an
- # additional gap for text spacing.
- esc_p CUF "$ascii_width"
-
- # Print the info name and color the text.
- esc_p SGR "3${PF_COL1-4}";
- esc_p SGR 1
- printf '%s' "$name"
- esc_p SGR 0
-
- # Print the info name and info data separator.
- printf %s "$PF_SEP"
-
- # Move the cursor backward the length of the *current* info name and
- # then move it forwards the length of the *longest* info name. This
- # aligns each info data line.
- esc_p CUB "${#name}"
- esc_p CUF "${PF_ALIGN:-$info_length}"
-
- # Print the info data, color it and strip all leading whitespace
- # from the string.
- esc_p SGR "3${PF_COL2-7}"
- printf '%s' "$info"
- esc_p SGR 0
- printf '\n'
-
- # Keep track of the number of times 'log()' has been run.
- info_height=$((${info_height:-0} + 1))
- }
-
- get_title() {
- # Username is retrieved by first checking '$USER' with a fallback
- # to the 'id -un' command.
- user=${USER:-$(id -un)}
-
- # Hostname is retrieved by first checking '$HOSTNAME' with a fallback
- # to the 'hostname' command.
- #
- # Disable the warning about '$HOSTNAME' being undefined in POSIX sh as
- # the intention for using it is allowing the user to overwrite the
- # value on invocation.
- # shellcheck disable=SC2039
- host=${HOSTNAME:-${host:-$(hostname)}}
-
- # If the hostname is still not found, fallback to the contents of the
- # /etc/hostname file.
- [ "$host" ] || read -r host < /etc/hostname
-
- # Add escape sequences for coloring to user and host name. As we embed
- # them directly in the arguments passed to log(), we cannot use esc_p().
- esc SGR 1
- user=$e$user
- esc SGR "3${PF_COL3:-1}"
- user=$e$user
- esc SGR 1
- user=$user$e
- esc SGR 1
- host=$e$host
- esc SGR "3${PF_COL3:-1}"
- host=$e$host
-
- log "${user}@${host}" " " >&6
- }
-
- get_os() {
- # This function is called twice, once to detect the distribution name
- # for the purposes of picking an ascii art early and secondly to display
- # the distribution name in the info output (if enabled).
- #
- # On first run, this function displays _nothing_, only on the second
- # invocation is 'log()' called.
- [ "$distro" ] && {
- log os "$distro" >&6
- return
- }
-
- case $os in
- (Linux*)
- # Some Linux distributions (which are based on others)
- # fail to identify as they **do not** change the upstream
- # distribution's identification packages or files.
- #
- # It is senseless to add a special case in the code for
- # each and every distribution (which _is_ technically no
- # different from what it is based on) as they're either too
- # lazy to modify upstream's identification files or they
- # don't have the know-how (or means) to ship their own
- # lsb-release package.
- #
- # This causes users to think there's a bug in system detection
- # tools like neofetch or pfetch when they technically *do*
- # function correctly.
- #
- # Exceptions are made for distributions which are independent,
- # not based on another distribution or follow different
- # standards.
- #
- # This applies only to distributions which follow the standard
- # by shipping unmodified identification files and packages
- # from their respective upstreams.
- if has lsb_release; then
- distro=$(lsb_release -sd)
-
- # Android detection works by checking for the existence of
- # the follow two directories. I don't think there's a simpler
- # method than this.
- elif [ -d /system/app ] && [ -d /system/priv-app ]; then
- distro="Android $(getprop ro.build.version.release)"
-
- else
- # This used to be a simple '. /etc/os-release' but I believe
- # this is insecure as we blindly executed whatever was in the
- # file. This parser instead simply handles 'key=val', treating
- # the file contents as plain-text.
- while IFS='=' read -r key val; do
- case $key in
- (PRETTY_NAME)
- distro=$val
- ;;
- esac
- done < /etc/os-release
- fi
-
- # 'os-release' and 'lsb_release' sometimes add quotes
- # around the distribution name, strip them.
- distro=${distro##[\"\']}
- distro=${distro%%[\"\']}
-
- # Special cases for (independent) distributions which
- # don't follow any os-release/lsb standards whatsoever.
- has crux && distro=$(crux)
- has guix && distro='Guix System'
-
- # Check to see if we're running Bedrock Linux which is
- # very unique. This simply checks to see if the user's
- # PATH contains a Bedrock specific value.
- case $PATH in
- (*/bedrock/cross/*)
- distro='Bedrock Linux'
- ;;
- esac
-
- # Check to see if Linux is running in Windows 10 under
- # WSL1 (Windows subsystem for Linux [version 1]) and
- # append a string accordingly.
- #
- # If the kernel version string ends in "-Microsoft",
- # we're very likely running under Windows 10 in WSL1.
- if [ "$WSLENV" ]; then
- distro="${distro}${WSLENV+ on Windows 10 [WSL2]}"
-
- # Check to see if Linux is running in Windows 10 under
- # WSL2 (Windows subsystem for Linux [version 2]) and
- # append a string accordingly.
- #
- # This checks to see if '$WSLENV' is defined. This
- # appends the Windows 10 string even if '$WSLENV' is
- # empty. We only need to check that is has been _exported_.
- elif [ -z "${kernel%%*-Microsoft}" ]; then
- distro="$distro on Windows 10 [WSL1]"
- fi
- ;;
-
- (Darwin*)
- # Parse the SystemVersion.plist file to grab the macOS
- # version. The file is in the following format:
- #
- # <key>ProductVersion</key>
- # <string>10.14.6</string>
- #
- # 'IFS' is set to '<>' to enable splitting between the
- # keys and a second 'read' is used to operate on the
- # next line directly after a match.
- #
- # '_' is used to nullify a field. '_ _ line _' basically
- # says "populate $line with the third field's contents".
- while IFS='<>' read -r _ _ line _; do
- case $line in
- # Match 'ProductVersion' and read the next line
- # directly as it contains the key's value.
- ProductVersion)
- IFS='<>' read -r _ _ mac_version _
- continue
- ;;
-
- ProductName)
- IFS='<>' read -r _ _ mac_product _
- continue
- ;;
- esac
- done < /System/Library/CoreServices/SystemVersion.plist
-
- # Use the ProductVersion to determine which macOS/OS X codename
- # the system has. As far as I'm aware there's no "dynamic" way
- # of grabbing this information.
- case $mac_version in
- (10.4*) distro='Mac OS X Tiger' ;;
- (10.5*) distro='Mac OS X Leopard' ;;
- (10.6*) distro='Mac OS X Snow Leopard' ;;
- (10.7*) distro='Mac OS X Lion' ;;
- (10.8*) distro='OS X Mountain Lion' ;;
- (10.9*) distro='OS X Mavericks' ;;
- (10.10*) distro='OS X Yosemite' ;;
- (10.11*) distro='OS X El Capitan' ;;
- (10.12*) distro='macOS Sierra' ;;
- (10.13*) distro='macOS High Sierra' ;;
- (10.14*) distro='macOS Mojave' ;;
- (10.15*) distro='macOS Catalina' ;;
- (11*) distro='macOS Big Sur' ;;
- (*) distro='macOS' ;;
- esac
-
- # Use the ProductName to determine if we're running in iOS.
- case $mac_product in
- (iP*) distro='iOS' ;;
- esac
-
- distro="$distro $mac_version"
- ;;
-
- (Haiku)
- # Haiku uses 'uname -v' for version information
- # instead of 'uname -r' which only prints '1'.
- distro=$(uname -sv)
- ;;
-
- (Minix|DragonFly)
- distro="$os $kernel"
-
- # Minix and DragonFly don't support the escape
- # sequences used, clear the exit trap.
- trap '' EXIT
- ;;
-
- (SunOS)
- # Grab the first line of the '/etc/release' file
- # discarding everything after '('.
- IFS='(' read -r distro _ < /etc/release
- ;;
-
- (OpenBSD*)
- # Show the OpenBSD version type (current if present).
- # kern.version=OpenBSD 6.6-current (GENERIC.MP) ...
- IFS=' =' read -r _ distro openbsd_ver _ <<-EOF
- $(sysctl kern.version)
- EOF
-
- distro="$distro $openbsd_ver"
- ;;
-
- FreeBSD)
- distro="$os $(freebsd-version)"
- ;;
-
- (*)
- # Catch all to ensure '$distro' is never blank.
- # This also handles the BSDs.
- distro="$os $kernel"
- ;;
- esac
- }
-
- get_kernel() {
- case $os in
- # Don't print kernel output on some systems as the
- # OS name includes it.
- (*BSD*|Haiku|Minix)
- return
- ;;
- esac
-
- # '$kernel' is the cached output of 'uname -r'.
- log kernel "$kernel" >&6
- }
-
- get_host() {
- case $os in
- (Linux*)
- # Despite what these files are called, version doesn't
- # always contain the version nor does name always contain
- # the name.
- read -r name < /sys/devices/virtual/dmi/id/product_name
- read -r version < /sys/devices/virtual/dmi/id/product_version
- read -r model < /sys/firmware/devicetree/base/model
-
- host="$name $version $model"
- ;;
-
- (Darwin* | FreeBSD* | DragonFly*)
- host=$(sysctl -n hw.model)
- ;;
-
- (NetBSD*)
- host=$(sysctl -n machdep.dmi.system-vendor \
- machdep.dmi.system-product)
- ;;
-
- (OpenBSD*)
- host=$(sysctl -n hw.version)
- ;;
-
- (*BSD* | Minix)
- host=$(sysctl -n hw.vendor hw.product)
- ;;
- esac
-
- # Turn the host string into an argument list so we can iterate
- # over it and remove OEM strings and other information which
- # shouldn't be displayed.
- #
- # Disable the shellcheck warning for word-splitting
- # as it's safe and intended ('set -f' disables globbing).
- # shellcheck disable=2046,2086
- {
- set -f
- set +f -- $host
- host=
- }
-
- # Iterate over the host string word by word as a means of stripping
- # unwanted and OEM information from the string as a whole.
- #
- # This could have been implemented using a long 'sed' command with
- # a list of word replacements, however I want to show that something
- # like this is possible in pure sh.
- #
- # This string reconstruction is needed as some OEMs either leave the
- # identification information as "To be filled by OEM", "Default",
- # "undefined" etc and we shouldn't print this to the screen.
- for word do
- # This works by reconstructing the string by excluding words
- # found in the "blacklist" below. Only non-matches are appended
- # to the final host string.
- case $word in
- (To | [Bb]e | [Ff]illed | [Bb]y | O.E.M. | OEM |\
- Not | Applicable | Specified | System | Product | Name |\
- Version | Undefined | Default | string | INVALID | � | os |\
- Type1ProductConfigId )
- continue
- ;;
- esac
-
- host="$host$word "
- done
-
- # '$arch' is the cached output from 'uname -m'.
- log host "${host:-$arch}" >&6
- }
-
- get_uptime() {
- # Uptime works by retrieving the data in total seconds and then
- # converting that data into days, hours and minutes using simple
- # math.
- case $os in
- (Linux* | Minix*)
- IFS=. read -r s _ < /proc/uptime
- ;;
-
- Darwin* | *BSD* | DragonFly*)
- s=$(sysctl -n kern.boottime)
-
- # Extract the uptime in seconds from the following output:
- # [...] { sec = 1271934886, usec = 667779 } Thu Apr 22 12:14:46 2010
- s=${s#*=}
- s=${s%,*}
-
- # The uptime format from 'sysctl' needs to be subtracted from
- # the current time in seconds.
- s=$(($(date +%s) - s))
- ;;
-
- (Haiku)
- # The boot time is returned in microseconds, convert it to
- # regular seconds.
- s=$(($(system_time) / 1000000))
- ;;
-
- (SunOS)
- # Split the output of 'kstat' on '.' and any white-space
- # which exists in the command output.
- #
- # The output is as follows:
- # unix:0:system_misc:snaptime 14809.906993005
- #
- # The parser extracts: ^^^^^
- IFS=' .' read -r _ s _ <<-EOF
- $(kstat -p unix:0:system_misc:snaptime)
- EOF
- ;;
-
- (IRIX)
- # Grab the uptime in a pretty format. Usually,
- # 00:00:00 from the 'ps' command.
- t=$(LC_ALL=POSIX ps -o etime= -p 1)
-
- # Split the pretty output into days or hours
- # based on the uptime.
- case $t in
- (*-*) d=${t%%-*} t=${t#*-} ;;
- (*:*:*) h=${t%%:*} t=${t#*:} ;;
- esac
-
- h=${h#0} t=${t#0}
-
- # Convert the split pretty fields back into
- # seconds so we may re-convert them to our format.
- s=$((${d:-0}*86400 + ${h:-0}*3600 + ${t%%:*}*60 + ${t#*:}))
- ;;
- esac
-
- # Convert the uptime from seconds into days, hours and minutes.
- d=$((s / 60 / 60 / 24))
- h=$((s / 60 / 60 % 24))
- m=$((s / 60 % 60))
-
- # Only append days, hours and minutes if they're non-zero.
- case "$d" in ([!0]*) uptime="${uptime}${d}d "; esac
- case "$h" in ([!0]*) uptime="${uptime}${h}h "; esac
- case "$m" in ([!0]*) uptime="${uptime}${m}m "; esac
-
- log uptime "${uptime:-0m}" >&6
- }
-
- get_pkgs() {
- # This works by first checking for which package managers are
- # installed and finally by printing each package manager's
- # package list with each package one per line.
- #
- # The output from this is then piped to 'wc -l' to count each
- # line, giving us the total package count of whatever package
- # managers are installed.
- #
- # Backticks are *required* here as '/bin/sh' on macOS is
- # 'bash 3.2' and it can't handle the following:
- #
- # var=$(
- # code here
- # )
- #
- # shellcheck disable=2006
- packages=`
- case $os in
- (Linux*)
- # Commands which print packages one per line.
- has bonsai && bonsai list
- has crux && pkginfo -i
- has pacman-key && pacman -Qq
- has dpkg && dpkg-query -f '.\n' -W
- has rpm && rpm -qa
- has xbps-query && xbps-query -l
- has apk && apk info
- has guix && guix package --list-installed
- has opkg && opkg list-installed
-
- # Directories containing packages.
- has kiss && printf '%s\n' /var/db/kiss/installed/*/
- has cpt-list && printf '%s\n' /var/db/cpt/installed/*/
- has brew && printf '%s\n' "$(brew --cellar)/"*
- has emerge && printf '%s\n' /var/db/pkg/*/*/
- has pkgtool && printf '%s\n' /var/log/packages/*
- has eopkg && printf '%s\n' /var/lib/eopkg/package/*
-
- # 'nix' requires two commands.
- has nix-store && {
- nix-store -q --requisites /run/current-system/sw
- nix-store -q --requisites ~/.nix-profile
- }
- ;;
-
- (Darwin*)
- # Commands which print packages one per line.
- has pkgin && pkgin list
- has dpkg && dpkg-query -f '.\n' -W
-
- # Directories containing packages.
- has brew && printf '%s\n' /usr/local/Cellar/*
-
- # 'port' prints a single line of output to 'stdout'
- # when no packages are installed and exits with
- # success causing a false-positive of 1 package
- # installed.
- #
- # 'port' should really exit with a non-zero code
- # in this case to allow scripts to cleanly handle
- # this behavior.
- has port && {
- pkg_list=$(port installed)
-
- case "$pkg_list" in
- ("No ports are installed.")
- # do nothing
- ;;
-
- (*)
- printf '%s\n' "$pkg_list"
- ;;
- esac
- }
- ;;
-
- (FreeBSD*|DragonFly*)
- pkg info
- ;;
-
- (OpenBSD*)
- printf '%s\n' /var/db/pkg/*/
- ;;
-
- (NetBSD*)
- pkg_info
- ;;
-
- (Haiku)
- printf '%s\n' /boot/system/package-links/*
- ;;
-
- (Minix)
- printf '%s\n' /usr/pkg/var/db/pkg/*/
- ;;
-
- (SunOS)
- has pkginfo && pkginfo -i
- has pkg && pkg list
- ;;
-
- (IRIX)
- versions -b
- ;;
- esac | wc -l
- `
-
- case $os in
- # IRIX's package manager adds 3 lines of extra
- # output which we must account for here.
- (IRIX)
- packages=$((packages - 3))
- ;;
-
- # OpenBSD's wc prints whitespace before the output
- # which needs to be stripped.
- (OpenBSD)
- packages=$((packages))
- ;;
- esac
-
- case $packages in
- (1?*|[2-9]*)
- log pkgs "$packages" >&6
- ;;
- esac
- }
-
- get_memory() {
- case $os in
- # Used memory is calculated using the following "formula":
- # MemUsed = MemTotal + Shmem - MemFree - Buffers - Cached - SReclaimable
- # Source: https://github.com/KittyKatt/screenFetch/issues/386
- (Linux*)
- # Parse the '/proc/meminfo' file splitting on ':' and 'k'.
- # The format of the file is 'key: 000kB' and an additional
- # split is used on 'k' to filter out 'kB'.
- while IFS=':k ' read -r key val _; do
- case $key in
- (MemTotal)
- mem_used=$((mem_used + val))
- mem_full=$val
- ;;
-
- (Shmem)
- mem_used=$((mem_used + val))
- ;;
-
- (MemFree | Buffers | Cached | SReclaimable)
- mem_used=$((mem_used - val))
- ;;
-
- # If detected this will be used over the above calculation
- # for mem_used. Available since Linux 3.14rc.
- # See kernel commit 34e431b0ae398fc54ea69ff85ec700722c9da773
- (MemAvailable)
- mem_avail=$val
- ;;
- esac
- done < /proc/meminfo
-
- case $mem_avail in
- (*[0-9]*)
- mem_used=$(((mem_full - mem_avail) / 1024))
- ;;
-
- *)
- mem_used=$((mem_used / 1024))
- ;;
- esac
-
- mem_full=$((mem_full / 1024))
- ;;
-
- # Used memory is calculated using the following "formula":
- # (wired + active + occupied) * 4 / 1024
- (Darwin*)
- mem_full=$(($(sysctl -n hw.memsize) / 1024 / 1024))
-
- # Parse the 'vmstat' file splitting on ':' and '.'.
- # The format of the file is 'key: 000.' and an additional
- # split is used on '.' to filter it out.
- while IFS=:. read -r key val; do
- case $key in
- (*' wired'*|*' active'*|*' occupied'*)
- mem_used=$((mem_used + ${val:-0}))
- ;;
- esac
-
- # Using '<<-EOF' is the only way to loop over a command's
- # output without the use of a pipe ('|').
- # This ensures that any variables defined in the while loop
- # are still accessible in the script.
- done <<-EOF
- $(vm_stat)
- EOF
-
- mem_used=$((mem_used * 4 / 1024))
- ;;
-
- (OpenBSD*)
- mem_full=$(($(sysctl -n hw.physmem) / 1024 / 1024))
-
- # This is a really simpler parser for 'vmstat' which grabs
- # the used memory amount in a lazy way. 'vmstat' prints 3
- # lines of output with the needed value being stored in the
- # final line.
- #
- # This loop simply grabs the 3rd element of each line until
- # the EOF is reached. Each line overwrites the value of the
- # previous one so we're left with what we wanted. This isn't
- # slow as only 3 lines are parsed.
- while read -r _ _ line _; do
- mem_used=${line%%M}
-
- # Using '<<-EOF' is the only way to loop over a command's
- # output without the use of a pipe ('|').
- # This ensures that any variables defined in the while loop
- # are still accessible in the script.
- done <<-EOF
- $(vmstat)
- EOF
- ;;
-
- # Used memory is calculated using the following "formula":
- # mem_full - ((inactive + free + cache) * page_size / 1024)
- (FreeBSD*|DragonFly*)
- mem_full=$(($(sysctl -n hw.physmem) / 1024 / 1024))
-
- # Use 'set --' to store the output of the command in the
- # argument list. POSIX sh has no arrays but this is close enough.
- #
- # Disable the shellcheck warning for word-splitting
- # as it's safe and intended ('set -f' disables globbing).
- # shellcheck disable=2046
- {
- set -f
- set +f -- $(sysctl -n hw.pagesize \
- vm.stats.vm.v_inactive_count \
- vm.stats.vm.v_free_count \
- vm.stats.vm.v_cache_count)
- }
-
- # Calculate the amount of used memory.
- # $1: hw.pagesize
- # $2: vm.stats.vm.v_inactive_count
- # $3: vm.stats.vm.v_free_count
- # $4: vm.stats.vm.v_cache_count
- mem_used=$((mem_full - (($2 + $3 + $4) * $1 / 1024 / 1024)))
- ;;
-
- (NetBSD*)
- mem_full=$(($(sysctl -n hw.physmem64) / 1024 / 1024))
-
- # NetBSD implements a lot of the Linux '/proc' filesystem,
- # this uses the same parser as the Linux memory detection.
- while IFS=':k ' read -r key val _; do
- case $key in
- (MemFree)
- mem_free=$((val / 1024))
- break
- ;;
- esac
- done < /proc/meminfo
-
- mem_used=$((mem_full - mem_free))
- ;;
-
- (Haiku)
- # Read the first line of 'sysinfo -mem' splitting on
- # '(', ' ', and ')'. The needed information is then
- # stored in the 5th and 7th elements. Using '_' "consumes"
- # an element allowing us to proceed to the next one.
- #
- # The parsed format is as follows:
- # 3501142016 bytes free (used/max 792645632 / 4293787648)
- IFS='( )' read -r _ _ _ _ mem_used _ mem_full <<-EOF
- $(sysinfo -mem)
- EOF
-
- mem_used=$((mem_used / 1024 / 1024))
- mem_full=$((mem_full / 1024 / 1024))
- ;;
-
- (Minix)
- # Minix includes the '/proc' filesystem though the format
- # differs from Linux. The '/proc/meminfo' file is only a
- # single line with space separated elements and elements
- # 2 and 3 contain the total and free memory numbers.
- read -r _ mem_full mem_free _ < /proc/meminfo
-
- mem_used=$(((mem_full - mem_free) / 1024))
- mem_full=$(( mem_full / 1024))
- ;;
-
- (SunOS)
- hw_pagesize=$(pagesize)
-
- # 'kstat' outputs memory in the following format:
- # unix:0:system_pages:pagestotal 1046397
- # unix:0:system_pages:pagesfree 885018
- #
- # This simply uses the first "element" (white-space
- # separated) as the key and the second element as the
- # value.
- #
- # A variable is then assigned based on the key.
- while read -r key val; do
- case $key in
- (*total)
- pages_full=$val
- ;;
-
- (*free)
- pages_free=$val
- ;;
- esac
- done <<-EOF
- $(kstat -p unix:0:system_pages:pagestotal \
- unix:0:system_pages:pagesfree)
- EOF
-
- mem_full=$((pages_full * hw_pagesize / 1024 / 1024))
- mem_free=$((pages_free * hw_pagesize / 1024 / 1024))
- mem_used=$((mem_full - mem_free))
- ;;
-
- (IRIX)
- # Read the memory information from the 'top' command. Parse
- # and split each line until we reach the line starting with
- # "Memory".
- #
- # Example output: Memory: 160M max, 147M avail, .....
- while IFS=' :' read -r label mem_full _ mem_free _; do
- case $label in
- (Memory)
- mem_full=${mem_full%M}
- mem_free=${mem_free%M}
- break
- ;;
- esac
- done <<-EOF
- $(top -n)
- EOF
-
- mem_used=$((mem_full - mem_free))
- ;;
- esac
-
- log memory "${mem_used:-?}M / ${mem_full:-?}M" >&6
- }
-
- get_wm() {
- case $os in
- (Darwin*)
- # Don't display window manager on macOS.
- ;;
-
- (*)
- # xprop can be used to grab the window manager's properties
- # which contains the window manager's name under '_NET_WM_NAME'.
- #
- # The upside to using 'xprop' is that you don't need to hardcode
- # a list of known window manager names. The downside is that
- # not all window managers conform to setting the '_NET_WM_NAME'
- # atom..
- #
- # List of window managers which fail to set the name atom:
- # catwm, fvwm, dwm, 2bwm, monster, wmaker and sowm [mine! ;)].
- #
- # The final downside to this approach is that it does _not_
- # support Wayland environments. The only solution which supports
- # Wayland is the 'ps' parsing mentioned below.
- #
- # A more naive implementation is to parse the last line of
- # '~/.xinitrc' to extract the second white-space separated
- # element.
- #
- # The issue with an approach like this is that this line data
- # does not always equate to the name of the window manager and
- # could in theory be _anything_.
- #
- # This also fails when the user launches xorg through a display
- # manager or other means.
- #
- #
- # Another naive solution is to parse 'ps' with a hardcoded list
- # of window managers to detect the current window manager (based
- # on what is running).
- #
- # The issue with this approach is the need to hardcode and
- # maintain a list of known window managers.
- #
- # Another issue is that process names do not always equate to
- # the name of the window manager. False-positives can happen too.
- #
- # This is the only solution which supports Wayland based
- # environments sadly. It'd be nice if some kind of standard were
- # established to identify Wayland environments.
- #
- # pfetch's goal is to remain _simple_, if you'd like a "full"
- # implementation of window manager detection use 'neofetch'.
- #
- # Neofetch use a combination of 'xprop' and 'ps' parsing to
- # support all window managers (including non-conforming and
- # Wayland) though it's a lot more complicated!
-
- # Don't display window manager if X isn't running.
- [ "$DISPLAY" ] || return
-
- # This is a two pass call to xprop. One call to get the window
- # manager's ID and another to print its properties.
- has xprop && {
- # The output of the ID command is as follows:
- # _NET_SUPPORTING_WM_CHECK: window id # 0x400000
- #
- # To extract the ID, everything before the last space
- # is removed.
- id=$(xprop -root -notype _NET_SUPPORTING_WM_CHECK)
- id=${id##* }
-
- # The output of the property command is as follows:
- # _NAME 8t
- # _NET_WM_PID = 252
- # _NET_WM_NAME = "bspwm"
- # _NET_SUPPORTING_WM_CHECK: window id # 0x400000
- # WM_CLASS = "wm", "Bspwm"
- #
- # To extract the name, everything before '_NET_WM_NAME = \"'
- # is removed and everything after the next '"' is removed.
- wm=$(xprop -id "$id" -notype -len 25 -f _NET_WM_NAME 8t)
- }
-
- # Handle cases of a window manager _not_ populating the
- # '_NET_WM_NAME' atom. Display nothing in this case.
- case $wm in
- (*'_NET_WM_NAME = '*)
- wm=${wm##*_NET_WM_NAME = \"}
- wm=${wm%%\"*}
- ;;
-
- (*)
- # Fallback to checking the process list
- # for the select few window managers which
- # don't set '_NET_WM_NAME'.
- while read -r ps_line; do
- case $ps_line in
- (*catwm*) wm=catwm ;;
- (*fvwm*) wm=fvwm ;;
- (*dwm*) wm=dwm ;;
- (*2bwm*) wm=2bwm ;;
- (*monsterwm*) wm=monsterwm ;;
- (*wmaker*) wm='Window Maker' ;;
- (*sowm*) wm=sowm ;;
- esac
- done <<-EOF
- $(ps x)
- EOF
- ;;
- esac
- ;;
- esac
-
- log wm "$wm" >&6
- }
-
-
- get_de() {
- # This only supports Xorg related desktop environments though
- # this is fine as knowing the desktop environment on Windows,
- # macOS etc is useless (they'll always report the same value).
- #
- # Display the value of '$XDG_CURRENT_DESKTOP', if it's empty,
- # display the value of '$DESKTOP_SESSION'.
- log de "${XDG_CURRENT_DESKTOP:-$DESKTOP_SESSION}" >&6
- }
-
- get_shell() {
- # Display the basename of the '$SHELL' environment variable.
- log shell "${SHELL##*/}" >&6
- }
-
- get_editor() {
- # Display the value of '$VISUAL', if it's empty, display the
- # value of '$EDITOR'.
- log editor "${VISUAL:-$EDITOR}" >&6
- }
-
- get_palette() {
- # Print the first 8 terminal colors. This uses the existing
- # sequences to change text color with a sequence prepended
- # to reverse the foreground and background colors.
- #
- # This allows us to save hardcoding a second set of sequences
- # for background colors.
- #
- # False positive.
- # shellcheck disable=2154
- {
- esc SGR 7
- palette="$e$c1 $c1 $c2 $c2 $c3 $c3 $c4 $c4 $c5 $c5 $c6 $c6 "
- esc SGR 0
- palette="$palette$e"
- }
-
- # Print the palette with a new-line before and afterwards.
- printf '\n' >&6
- log "$palette
- " " " >&6
- }
-
- get_ascii() {
- # This is a simple function to read the contents of
- # an ascii file from 'stdin'. It allows for the use
- # of '<<-EOF' to prevent the break in indentation in
- # this source code.
- #
- # This function also sets the text colors according
- # to the ascii color.
- read_ascii() {
- # 'PF_COL1': Set the info name color according to ascii color.
- # 'PF_COL3': Set the title color to some other color. ¯\_(ツ)_/¯
- PF_COL1=${PF_COL1:-${1:-7}}
- PF_COL3=${PF_COL3:-$((${1:-7}%8+1))}
-
- # POSIX sh has no 'var+=' so 'var=${var}append' is used. What's
- # interesting is that 'var+=' _is_ supported inside '$(())'
- # (arithmetic) though there's no support for 'var++/var--'.
- #
- # There is also no $'\n' to add a "literal"(?) newline to the
- # string. The simplest workaround being to break the line inside
- # the string (though this has the caveat of breaking indentation).
- while IFS= read -r line; do
- ascii="$ascii$line
- "
- done
- }
-
- # This checks for ascii art in the following order:
- # '$1': Argument given to 'get_ascii()' directly.
- # '$PF_ASCII': Environment variable set by user.
- # '$distro': The detected distribution name.
- # '$os': The name of the operating system/kernel.
- #
- # NOTE: Each ascii art below is indented using tabs, this
- # allows indentation to continue naturally despite
- # the use of '<<-EOF'.
- #
- # False positive.
- # shellcheck disable=2154
- case ${1:-${PF_ASCII:-${distro:-$os}}} in
- ([Aa]lpine*)
- read_ascii 4 <<-EOF
- ${c4} /\\ /\\
- /${c7}/ ${c4}\\ \\
- /${c7}/ ${c4}\\ \\
- /${c7}// ${c4}\\ \\
- ${c7}// ${c4}\\ \\
- ${c4}\\
- EOF
- ;;
-
- ([Aa]ndroid*)
- read_ascii 2 <<-EOF
- ${c2} ;, ,;
- ${c2} ';,.-----.,;'
- ${c2} ,' ',
- ${c2} / O O \\
- ${c2}| |
- ${c2}'-----------------'
- EOF
- ;;
-
- ([Aa]rch*)
- read_ascii 4 <<-EOF
- ${c6} /\\
- ${c6} / \\
- ${c6} /\\ \\
- ${c4} / \\
- ${c4} / ,, \\
- ${c4} / | | -\\
- ${c4} /_-'' ''-_\\
- EOF
- ;;
-
- ([Aa]rco*)
- read_ascii 4 <<-EOF
- ${c4} /\\
- ${c4} / \\
- ${c4} / /\\ \\
- ${c4} / / \\ \\
- ${c4} / / \\ \\
- ${c4} / / _____\\ \\
- ${c4}/_/ \`----.\\_\\
- EOF
- ;;
-
- ([Aa]rtix*)
- read_ascii 6 <<-EOF
- ${c4} /\\
- ${c4} / \\
- ${c4} /\`'.,\\
- ${c4} / ',
- ${c4} / ,\`\\
- ${c4} / ,.'\`. \\
- ${c4}/.,'\` \`'.\\
- EOF
- ;;
-
- ([Bb]edrock*)
- read_ascii 4 <<-EOF
- ${c7}__
- ${c7}\\ \\___
- ${c7} \\ _ \\
- ${c7} \\___/
- EOF
- ;;
-
- ([Bb]uildroot*)
- read_ascii 3 <<-EOF
- ${c3} ___
- ${c3} / \` \\
- ${c3}| : :|
- ${c3}-. _:__.-
- ${c3} \` ---- \`
- EOF
- ;;
-
- ([Cc]ent[Oo][Ss]*)
- read_ascii 5 <<-EOF
- ${c2} ____${c3}^${c5}____
- ${c2} |\\ ${c3}|${c5} /|
- ${c2} | \\ ${c3}|${c5} / |
- ${c5}<---- ${c4}---->
- ${c4} | / ${c2}|${c3} \\ |
- ${c4} |/__${c2}|${c3}__\\|
- ${c2} v
- EOF
- ;;
-
- ([Dd]ahlia*)
- read_ascii 1 <<-EOF
- ${c1} _
- ${c1} ___/ \\___
- ${c1} | _-_ |
- ${c1} | / \ |
- ${c1}/ | | \\
- ${c1}\\ | | /
- ${c1} | \ _ _ / |
- ${c1} |___ - ___|
- ${c1} \\_/
- EOF
- ;;
-
- ([Dd]ebian*)
- read_ascii 1 <<-EOF
- ${c1} _____
- ${c1} / __ \\
- ${c1}| / |
- ${c1}| \\___-
- ${c1}-_
- ${c1} --_
- EOF
- ;;
-
- ([Dd]ragon[Ff]ly*)
- read_ascii 1 <<-EOF
- ,${c1}_${c7},
- ('-_${c1}|${c7}_-')
- >--${c1}|${c7}--<
- (_-'${c1}|${c7}'-_)
- ${c1}|
- ${c1}|
- ${c1}|
- EOF
- ;;
-
- ([Ee]lementary*)
- read_ascii <<-EOF
- ${c7} _______
- ${c7} / ____ \\
- ${c7}/ | / /\\
- ${c7}|__\\ / / |
- ${c7}\\ /__/ /
- ${c7}\\_______/
- EOF
- ;;
-
- ([Ee]ndeavour*)
- read_ascii 4 <<-EOF
- ${c1}/${c4}\\
- ${c1}/${c4}/ \\${c6}\\
- ${c1}/${c4}/ \\ ${c6}\\
- ${c1}/ ${c4}/ _) ${c6})
- ${c1}/_${c4}/___-- ${c6}__-
- ${c6}/____--
- EOF
- ;;
-
- ([Ff]edora*)
- read_ascii 4 <<-EOF
- ${c4},'''''.
- ${c4}| ,. |
- ${c4}| | '_'
- ${c4} ,....| |..
- ${c4}.' ,_;| ..'
- ${c4}| | | |
- ${c4}| ',_,' |
- ${c4} '. ,'
- ${c4}'''''
- EOF
- ;;
-
- ([Ff]ree[Bb][Ss][Dd]*)
- read_ascii 1 <<-EOF
- ${c1}/\\,-'''''-,/\\
- ${c1}\\_) (_/
- ${c1}| |
- ${c1}| |
- ${c1}; ;
- ${c1}'-_____-'
- EOF
- ;;
-
- ([Gg]entoo*)
- read_ascii 5 <<-EOF
- ${c5} _-----_
- ${c5}( \\
- ${c5}\\ 0 \\
- ${c7} \\ )
- ${c7} / _/
- ${c7}( _-
- ${c7}\\____-
- EOF
- ;;
-
- ([Gg][Nn][Uu]*)
- read_ascii 3 <<-EOF
- ${c2} _-\`\`-, ,-\`\`-_
- ${c2} .' _-_| |_-_ '.
- ${c2}./ /_._ _._\\ \\.
- ${c2}: _/_._\`:'_._\\_ :
- ${c2}\\:._/ ,\` \\ \\ \\_.:/
- ${c2} ,-';'.@) \\ @) \\
- ${c2} ,'/' ..- .\\,-.|
- ${c2} /'/' \\(( \\\` ./ )
- ${c2} '/'' \\_,----'
- ${c2} '/'' ,;/''
- ${c2} \`\`;'
- EOF
- ;;
-
- ([Gg]uix[Ss][Dd]*|[Gg]uix*)
- read_ascii 3 <<-EOF
- ${c3}|.__ __.|
- ${c3}|__ \\ / __|
- ${c3}\\ \\ / /
- ${c3}\\ \\ / /
- ${c3}\\ \\ / /
- ${c3}\\ \\/ /
- ${c3}\\__/
- EOF
- ;;
-
- ([Hh]aiku*)
- read_ascii 3 <<-EOF
- ${c3} ,^,
- ${c3} / \\
- ${c3}*--_ ; ; _--*
- ${c3}\\ '" "' /
- ${c3}'. .'
- ${c3}.-'" "'-.
- ${c3}'-.__. .__.-'
- ${c3}|_|
- EOF
- ;;
-
- ([Hh]ydroOS*)
- read_ascii 4 <<-EOF
- ${c1}╔╗╔╗──╔╗───╔═╦══╗
- ${c1}║╚╝╠╦╦╝╠╦╦═╣║║══╣
- ${c1}║╔╗║║║╬║╔╣╬║║╠══║
- ${c1}╚╝╚╬╗╠═╩╝╚═╩═╩══╝
- ${c1}───╚═╝
- EOF
- ;;
-
- ([Hh]yperbola*)
- read_ascii <<-EOF
- ${c7} |\`__.\`/
- ${c7} \____/
- ${c7} .--.
- ${c7} / \\
- ${c7} / ___ \\
- ${c7}/ .\` \`.\\
- ${c7}/.\` \`.\\
- EOF
- ;;
-
- ([Ii]glunix*)
- read_ascii <<-EOF
- ${c0} |
- ${c0} | |
- ${c0} |
- ${c0} | ________
- ${c0} | /\\ | \\
- ${c0} / \\ | \\ |
- ${c0} / \\ \\ |
- ${c0} / \\________\\
- ${c0} \\ / /
- ${c0} \\ / /
- ${c0} \\ / /
- ${c0} \\/________/
- EOF
- ;;
-
- ([Ii]nstant[Oo][Ss]*)
- read_ascii <<-EOF
- ${c0} ,-''-,
- ${c0}: .''. :
- ${c0}: ',,' :
- ${c0} '-____:__
- ${c0} : \`.
- ${c0} \`._.'
- EOF
- ;;
-
- ([Ii][Rr][Ii][Xx]*)
- read_ascii 1 <<-EOF
- ${c1} __
- ${c1} \\ \\ __
- ${c1} \\ \\ / /
- ${c1} \\ v /
- ${c1} / . \\
- ${c1} /_/ \\ \\
- ${c1} \\_\\
- EOF
- ;;
-
- ([Kk][Dd][Ee]*[Nn]eon*)
- read_ascii 6 <<-EOF
- ${c7} .${c6}__${c7}.${c6}__${c7}.
- ${c6} / _${c7}.${c6}_ \\
- ${c6} / / \\ \\
- ${c7} . ${c6}| ${c7}O${c6} | ${c7}.
- ${c6} \\ \\_${c7}.${c6}_/ /
- ${c6} \\${c7}.${c6}__${c7}.${c6}__${c7}.${c6}/
- EOF
- ;;
-
- ([Ll]inux*[Ll]ite*|[Ll]ite*)
- read_ascii 3 <<-EOF
- ${c3} /\\
- ${c3} / \\
- ${c3} / ${c7}/ ${c3}/
- ${c3}> ${c7}/ ${c3}/
- ${c3}\\ ${c7}\\ ${c3}\\
- ${c3}\\_${c7}\\${c3}_\\
- ${c7} \\
- EOF
- ;;
-
- ([Ll]inux*[Mm]int*|[Mm]int)
- read_ascii 2 <<-EOF
- ${c2} ___________
- ${c2}|_ \\
- ${c2}| ${c7}| _____ ${c2}|
- ${c2}| ${c7}| | | | ${c2}|
- ${c2}| ${c7}| | | | ${c2}|
- ${c2}| ${c7}\\__${c7}___/ ${c2}|
- ${c2}\\_________/
- EOF
- ;;
-
-
- ([Ll]inux*)
- read_ascii 4 <<-EOF
- ${c4} ___
- ${c4}(${c7}.. ${c4}|
- ${c4}(${c5}<> ${c4}|
- ${c4}/ ${c7}__ ${c4}\\
- ${c4}( ${c7}/ \\ ${c4}/|
- ${c5}_${c4}/\\ ${c7}__)${c4}/${c5}_${c4})
- ${c5}\/${c4}-____${c5}\/
- EOF
- ;;
-
- ([Mm]ac[Oo][Ss]*|[Dd]arwin*)
- read_ascii 1 <<-EOF
- ${c2} .:'
- ${c2} _ :'_
- ${c3} .'\`_\`-'_\`\`.
- ${c1}:________.-'
- ${c1}:_______:
- ${c4} :_______\`-;
- ${c5} \`._.-._.'
- EOF
- ;;
-
- ([Mm]ageia*)
- read_ascii 2 <<-EOF
- ${c6} *
- ${c6} *
- ${c6} **
- ${c7} /\\__/\\
- ${c7}/ \\
- ${c7}\\ /
- ${c7} \\____/
- EOF
- ;;
-
- ([Mm]anjaro*)
- read_ascii 2 <<-EOF
- ${c2}||||||||| ||||
- ${c2}||||||||| ||||
- ${c2}|||| ||||
- ${c2}|||| |||| ||||
- ${c2}|||| |||| ||||
- ${c2}|||| |||| ||||
- ${c2}|||| |||| ||||
- EOF
- ;;
-
- ([Mm]inix*)
- read_ascii 4 <<-EOF
- ${c4} ,, ,,
- ${c4};${c7},${c4} ', ,' ${c7},${c4};
- ${c4}; ${c7}',${c4} ',,' ${c7},'${c4} ;
- ${c4}; ${c7}',${c4} ${c7},'${c4} ;
- ${c4}; ${c7};, '' ,;${c4} ;
- ${c4}; ${c7};${c4};${c7}',,'${c4};${c7};${c4} ;
- ${c4}', ${c7};${c4};; ;;${c7};${c4} ,'
- ${c4} '${c7};${c4}' '${c7};${c4}'
- EOF
- ;;
-
- ([Mm][Xx]*)
- read_ascii <<-EOF
- ${c7} \\\\ /
- ${c7} \\\\/
- ${c7} \\\\
- ${c7} /\\/ \\\\
- ${c7} / \\ /\\
- ${c7} / \\/ \\
- ${c7}/__________\\
- EOF
- ;;
-
- ([Nn]et[Bb][Ss][Dd]*)
- read_ascii 3 <<-EOF
- ${c7}\\\\${c3}\`-______,----__
- ${c7} \\\\ ${c3}__,---\`_
- ${c7} \\\\ ${c3}\`.____
- ${c7} \\\\${c3}-______,----\`-
- ${c7} \\\\
- ${c7} \\\\
- ${c7} \\\\
- EOF
- ;;
-
- ([Nn]ix[Oo][Ss]*)
- read_ascii 4 <<-EOF
- ${c4} \\\\ \\\\ //
- ${c4} ==\\\\__\\\\/ //
- ${c4} // \\\\//
- ${c4}==// //==
- ${c4} //\\\\___//
- ${c4}// /\\\\ \\\\==
- ${c4} // \\\\ \\\\
- EOF
- ;;
-
- ([Oo]pen[Bb][Ss][Dd]*)
- read_ascii 3 <<-EOF
- ${c3} _____
- ${c3} \\- -/
- ${c3} \\_/ \\
- ${c3} | ${c7}O O${c3} |
- ${c3} |_ < ) 3 )
- ${c3} / \\ /
- ${c3} /-_____-\\
- EOF
- ;;
-
- ([Oo]pen[Ss][Uu][Ss][Ee]*[Tt]umbleweed*)
- read_ascii 2 <<-EOF
- ${c2} _____ ______
- ${c2} / ____\\ / ____ \\
- ${c2}/ / \`/ / \\ \\
- ${c2}\\ \\____/ /,____/ /
- ${c2} \\______/ \\_____/
- EOF
- ;;
-
- ([Oo]pen[Ss][Uu][Ss][Ee]*|[Oo]pen*SUSE*|SUSE*|suse*)
- read_ascii 2 <<-EOF
- ${c2} _______
- ${c2}__| __ \\
- ${c2} / .\\ \\
- ${c2} \\__/ |
- ${c2} _______|
- ${c2} \\_______
- ${c2}__________/
- EOF
- ;;
-
- ([Oo]pen[Ww]rt*)
- read_ascii 1 <<-EOF
- ${c1} _______
- ${c1}| |.-----.-----.-----.
- ${c1}| - || _ | -__| |
- ${c1}|_______|| __|_____|__|__|
- ${c1} ________|__| __
- ${c1}| | | |.----.| |_
- ${c1}| | | || _|| _|
- ${c1}|________||__| |____|
- EOF
- ;;
-
- ([Pp]arabola*)
- read_ascii 5 <<-EOF
- ${c5} __ __ __ _
- ${c5}.\`_//_//_/ / \`.
- ${c5} / .\`
- ${c5} / .\`
- ${c5} /.\`
- ${c5} /\`
- EOF
- ;;
-
- ([Pp]op!_[Oo][Ss]*)
- read_ascii 6 <<-EOF
- ${c6}______
- ${c6}\\ _ \\ __
- ${c6}\\ \\ \\ \\ / /
- ${c6}\\ \\_\\ \\ / /
- ${c6}\\ ___\\ /_/
- ${c6} \\ \\ _
- ${c6} __\\_\\__(_)_
- ${c6}(___________)
- EOF
- ;;
-
- ([Pp]ure[Oo][Ss]*)
- read_ascii <<-EOF
- ${c7} _____________
- ${c7}| _________ |
- ${c7}| | | |
- ${c7}| | | |
- ${c7}| |_________| |
- ${c7}|_____________|
- EOF
- ;;
-
- ([Rr]aspbian*)
- read_ascii 1 <<-EOF
- ${c2} __ __
- ${c2} (_\\)(/_)
- ${c1} (_(__)_)
- ${c1}(_(_)(_)_)
- ${c1} (_(__)_)
- ${c1} (__)
- EOF
- ;;
-
- ([Ss]lackware*)
- read_ascii 4 <<-EOF
- ${c4} ________
- ${c4} / ______|
- ${c4} | |______
- ${c4} \\______ \\
- ${c4} ______| |
- ${c4}| |________/
- ${c4}|____________
- EOF
- ;;
-
- ([Ss]un[Oo][Ss]|[Ss]olaris*)
- read_ascii 3 <<-EOF
- ${c3} . .; .
- ${c3} . :; :: ;: .
- ${c3} .;. .. .. .;.
- ${c3}.. .. .. ..
- ${c3} .;, ,;.
- EOF
- ;;
-
- ([Uu]buntu*)
- read_ascii 3 <<-EOF
- ${c3} _
- ${c3} ---(_)
- ${c3} _/ --- \\
- ${c3}(_) | |
- ${c3} \\ --- _/
- ${c3} ---(_)
- EOF
- ;;
-
- ([Vv]oid*)
- read_ascii 2 <<-EOF
- ${c2} _______
- ${c2} _ \\______ -
- ${c2}| \\ ___ \\ |
- ${c2}| | / \ | |
- ${c2}| | \___/ | |
- ${c2}| \\______ \\_|
- ${c2} -_______\\
- EOF
- ;;
-
- ([Xx]eonix*)
- read_ascii 2 <<-EOF
- ${c2} ___ ___
- ${c2}___ \ \/ / ___
- ${c2}\ \ \ / / /
- ${c2} \ \/ \/ /
- ${c2} \ /\ /
- ${c2} \__/ \__/
- EOF
- ;;
-
- (*)
- # On no match of a distribution ascii art, this function calls
- # itself again, this time to look for a more generic OS related
- # ascii art (KISS Linux -> Linux).
- [ "$1" ] || {
- get_ascii "$os"
- return
- }
-
- printf 'error: %s is not currently supported.\n' "$os" >&6
- printf 'error: Open an issue for support to be added.\n' >&6
- exit 1
- ;;
- esac
-
- # Store the "width" (longest line) and "height" (number of lines)
- # of the ascii art for positioning. This script prints to the screen
- # *almost* like a TUI does. It uses escape sequences to allow dynamic
- # printing of the information through user configuration.
- #
- # Iterate over each line of the ascii art to retrieve the above
- # information. The 'sed' is used to strip '\033[3Xm' color codes from
- # the ascii art so they don't affect the width variable.
- while read -r line; do
- ascii_height=$((${ascii_height:-0} + 1))
-
- # This was a ternary operation but they aren't supported in
- # Minix's shell.
- [ "${#line}" -gt "${ascii_width:-0}" ] &&
- ascii_width=${#line}
-
- # Using '<<-EOF' is the only way to loop over a command's
- # output without the use of a pipe ('|').
- # This ensures that any variables defined in the while loop
- # are still accessible in the script.
- done <<-EOF
- $(printf %s "$ascii" | sed 's/\[3.m//g')
- EOF
-
- # Add a gap between the ascii art and the information.
- ascii_width=$((ascii_width + 4))
-
- # Print the ascii art and position the cursor back where we
- # started prior to printing it.
- {
- esc_p SGR 1
- printf '%s' "$ascii"
- esc_p SGR 0
- esc_p CUU "$ascii_height"
- } >&6
- }
-
- main() {
- [ "$1" = --version ] && {
- printf 'pfetch 0.7.0\n'
- exit 0
- }
-
- # Hide 'stderr' unless the first argument is '-v'. This saves
- # polluting the script with '2>/dev/null'.
- [ "$1" = -v ] || {
- exec 2>/dev/null
- }
-
- # Hide 'stdout' and selectively print to it using '>&6'.
- # This gives full control over what it displayed on the screen.
- exec 6>&1 >/dev/null
-
- # Store raw escape sequence character for later reuse.
- esc_c=$(printf '\033')
-
- # Allow the user to execute their own script and modify or
- # extend pfetch's behavior.
- # shellcheck source=/dev/null
- . "${PF_SOURCE:-/dev/null}" ||:
-
- # Ensure that the 'TMPDIR' is writable as heredocs use it and
- # fail without the write permission. This was found to be the
- # case on Android where the temporary directory requires root.
- [ -w "${TMPDIR:-/tmp}" ] || export TMPDIR=~
-
- # Generic color list.
- # Disable warning about unused variables.
- # shellcheck disable=2034
- for _c in c1 c2 c3 c4 c5 c6 c7 c8; do
- esc SGR "3${_c#?}" 0
- export "$_c=$e"
- done
-
- # Disable line wrapping and catch the EXIT signal to enable it again
- # on exit. Ideally you'd somehow query the current value and retain
- # it but I'm yet to see this irk anyone.
- esc_p DECAWM l >&6
- trap 'esc_p DECAWM h >&6' EXIT
-
- # Store the output of 'uname' to avoid calling it multiple times
- # throughout the script. 'read <<EOF' is the simplest way of reading
- # a command into a list of variables.
- read -r os kernel arch <<-EOF
- $(uname -srm)
- EOF
-
- # Always run 'get_os' for the purposes of detecting which ascii
- # art to display.
- get_os
-
- # Allow the user to specify the order and inclusion of information
- # functions through the 'PF_INFO' environment variable.
- # shellcheck disable=2086
- {
- # Disable globbing and set the positional parameters to the
- # contents of 'PF_INFO'.
- set -f
- set +f -- ${PF_INFO-ascii title os host kernel uptime pkgs memory}
-
- # Iterate over the info functions to determine the lengths of the
- # "info names" for output alignment. The option names and subtitles
- # match 1:1 so this is thankfully simple.
- for info do
- command -v "get_$info" >/dev/null || continue
-
- # This was a ternary operation but they aren't supported in
- # Minix's shell.
- [ "${#info}" -gt "${info_length:-0}" ] &&
- info_length=${#info}
- done
-
- # Add an additional space of length to act as a gap.
- info_length=$((info_length + 1))
-
- # Iterate over the above list and run any existing "get_" functions.
- for info do
- "get_$info"
- done
- }
-
- # Position the cursor below both the ascii art and information lines
- # according to the height of both. If the information exceeds the ascii
- # art in height, don't touch the cursor (0/unset), else move it down
- # N lines.
- #
- # This was a ternary operation but they aren't supported in Minix's shell.
- [ "${info_height:-0}" -lt "${ascii_height:-0}" ] &&
- cursor_pos=$((ascii_height - info_height))
-
- # Print '$cursor_pos' amount of newlines to correctly position the
- # cursor. This used to be a 'printf $(seq X X)' however 'seq' is only
- # typically available (by default) on GNU based systems!
- while [ "${i:=0}" -le "${cursor_pos:-0}" ]; do
- printf '\n'
- i=$((i + 1))
- done >&6
- }
-
- main "$@"
|