pfetch/pfetch

344 lines
11 KiB
Plaintext
Raw Normal View History

2019-09-24 09:33:23 +02:00
#!/bin/sh
#
# pfetch - Simple POSIX sh fetch script.
log() {
2019-09-24 11:47:47 +02:00
# 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.
#
# Once the cursor is at marker $[6], the script exits. This is the gist
# of how this "dynamic" printing and layout works.
#
2019-09-24 11:59:56 +02:00
# This method allows ascii art to be stored without markers for info
# and it allows for easy swapping of info order and amount.
2019-09-24 11:47:47 +02:00
#
# $[2] ___ $[3] goldie@KISS
# $[4](.· | $[5] os KISS Linux
# (<> |
# / __ \
# ( / \ /|
# _/\ __)/_)
# \/-____\/
# $[1]
#
# $[6] /home/goldie $
#
2019-09-24 14:14:12 +02:00
# '$PF_COL1': Control color of info name.
# '$PF_SEP': Control the separator between info name and info data.
# '$PF_COL2': Control color of info data.
# '$PF_ALIGN': Control the alignment amount.
2019-09-24 11:26:34 +02:00
#
2019-09-24 14:14:12 +02:00
# '\033[14C': Move cursor 14 characters to the right.
# TODO: Base this on ASCII art width.
2019-09-24 11:26:34 +02:00
#
2019-09-24 14:14:12 +02:00
# '\033[3%s': Color formatting.
# '\033[m': Reset formatting.
2019-09-24 11:26:34 +02:00
#
2019-09-24 14:14:12 +02:00
# '\033[%sD': Move cursor '${#1}' characters to the left.
# This allows for aligned info names and data.
2019-09-24 11:26:34 +02:00
#
2019-09-24 14:14:12 +02:00
# '\033[6C': Move cursor 6 characters to the right.
# This aligns the info.
2019-09-24 13:33:15 +02:00
#
# This is ugly, I know!
2019-09-24 13:41:20 +02:00
printf '\033[%sC\033[3%s;1m%s\033[m%s\033[3%sm\033[%sD\033[%sC%s\033[m\n' \
2019-09-24 13:33:15 +02:00
"${ascii_width:--1}" \
"${PF_COL1:-5}" \
"$1" \
2019-09-24 13:50:14 +02:00
"$PF_SEP" \
2019-09-24 13:33:15 +02:00
"${PF_COL2:-7}" \
"${#1}" \
2019-09-24 13:50:14 +02:00
"${PF_ALIGN:-$((info_length + 1))}" \
2019-09-24 13:41:20 +02:00
"$2"
2019-09-24 11:01:34 +02:00
# Keep track of the number of times 'log()' has been run.
2019-09-24 12:32:06 +02:00
info_height=$((info_height + 1))
2019-09-24 09:33:23 +02:00
}
2019-09-24 10:13:40 +02:00
get_title() {
2019-09-24 12:34:05 +02:00
case $os in
2019-09-24 11:59:02 +02:00
Linux*|GNU*)
2019-09-24 10:13:40 +02:00
read -r hostname < /proc/sys/kernel/hostname
;;
esac
# Username is retrieved by first checking '$USER' with a fallback
# to the 'whoami' command.
#
# Hostname is retrieved by first checking '$HOSTNAME' with a fallback
# to the OS specific detection above and finally an additional fallback
# to the 'hostname' command.
#
2019-09-24 10:25:06 +02:00
# Disable the warning about '$HOSTNAME' being undefined in POSIX sh as
# it is intended for allowing the user to overwrite the value on invocation.
2019-09-24 10:13:40 +02:00
# shellcheck disable=SC2039
2019-09-24 13:41:20 +02:00
log "$c4${USER:-$(whoami)}$c7@$c4${HOSTNAME:-${hostname:-$(hostname)}}"
2019-09-24 10:13:40 +02:00
}
2019-09-24 09:33:23 +02:00
get_distro() {
2019-09-24 12:34:05 +02:00
case $os in
2019-09-24 11:59:02 +02:00
Linux*|GNU*)
2019-09-24 14:01:41 +02:00
# Disable warning about shellcheck not being able
# to read '/etc/os-release'. This is fine.
# shellcheck source=/dev/null
2019-09-24 09:33:23 +02:00
. /etc/os-release && distro=$PRETTY_NAME
;;
esac
2019-09-24 10:25:06 +02:00
log os "$distro"
2019-09-24 09:33:23 +02:00
}
2019-09-24 09:46:56 +02:00
get_kernel() {
2019-09-24 12:34:05 +02:00
log kernel "$kernel"
2019-09-24 09:46:56 +02:00
}
2019-09-24 12:06:41 +02:00
get_host() {
2019-09-24 12:34:05 +02:00
case $os in
2019-09-24 12:06:41 +02:00
Linux*|GNU*)
2019-09-24 12:50:28 +02:00
# 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"
2019-09-24 12:06:41 +02:00
;;
esac
2019-09-24 12:38:46 +02:00
log host "$host"
2019-09-24 12:06:41 +02:00
}
2019-09-24 09:46:56 +02:00
get_uptime() {
2019-09-24 09:53:49 +02:00
# Uptime works by retrieving the data in total seconds and then
# converting that data into days, hours and minutes using simple
# math.
2019-09-24 12:34:05 +02:00
case $os in
2019-09-24 11:59:02 +02:00
Linux*|GNU*)
2019-09-24 09:46:56 +02:00
IFS=. read -r s _ < /proc/uptime
;;
esac
2019-09-24 09:53:49 +02:00
# Convert the uptime from seconds into days, hours and minutes.
2019-09-24 09:46:56 +02:00
d=$((s / 60 / 60 / 24))
h=$((s / 60 / 60 % 24))
m=$((s / 60 % 60))
2019-09-24 09:53:49 +02:00
# Only append days, hours and minutes if they're non-zero.
2019-09-24 09:46:56 +02:00
[ "$d" = 0 ] || uptime="${uptime}${d}d "
[ "$h" = 0 ] || uptime="${uptime}${h}h "
[ "$m" = 0 ] || uptime="${uptime}${m}m "
2019-09-24 10:25:06 +02:00
log uptime "${uptime:-0m}"
2019-09-24 09:46:56 +02:00
}
2019-09-24 13:41:20 +02:00
get_pkgs() {
# Simple function to avoid '>/dev/null' spam.
# This checks to see if a command is in '$PATH'.
has() { command -v "$1" >/dev/null; }
# This works by first checking for which package managers are
# isntalled 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.
packages=$(
2019-09-24 12:34:05 +02:00
case $os in
Linux*|GNU*)
# Commands which print packages one per line.
has kiss && kiss l
has bonsai && bonsai list
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
# Directories containing packages.
has brew && printf '%s\n' "$(brew --cellar)/"*
has emerge && printf '%s\n' /var/db/pkg/*/*/
;;
esac | wc -l
)
2019-09-24 12:06:41 +02:00
log pkgs "$packages"
}
2019-09-24 10:03:33 +02:00
get_memory() {
2019-09-24 12:34:05 +02:00
case $os in
2019-09-24 10:03:33 +02:00
# Used memory is calculated using the following "formula" (Linux):
# MemUsed = MemTotal + Shmem - MemFree - Buffers - Cached - SReclaimable
# Source: https://github.com/KittyKatt/screenFetch/issues/386
2019-09-24 11:59:02 +02:00
Linux*|GNU*)
2019-09-24 10:03:33 +02:00
# 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_total=$val
;;
Shmem)
mem_used=$((mem_used + val))
;;
MemFree|Buffers|Cached|SReclaimable)
mem_used=$((mem_used - val))
;;
esac
done < /proc/meminfo
mem_used=$((mem_used / 1024))
mem_total=$((mem_total / 1024))
;;
esac
2019-09-24 10:25:06 +02:00
log memory "${mem_used}MiB / ${mem_total}MiB"
2019-09-24 10:03:33 +02:00
}
2019-09-24 11:01:34 +02:00
get_ascii() {
2019-09-24 12:34:05 +02:00
case $os in
2019-09-24 11:59:02 +02:00
Linux*|GNU*)
2019-09-24 11:01:34 +02:00
ascii="\
${c4} ___
(${c7}.· ${c4}|
(${c5}<> ${c4}|
/ ${c7}__ ${c4}\\
2019-09-24 11:26:34 +02:00
( ${c7}/ \\ ${c4}/|
2019-09-24 11:01:34 +02:00
${c5}_${c4}/\\ ${c7}__)${c4}/${c5}_${c4})
${c5}\/${c4}-____${c5}\/
"
;;
2019-09-24 15:06:10 +02:00
*)
printf 'error: %s is not currently supported.\n' "$os"
printf 'error: Open an issue on GitHub for support to be added.\n'
exit 1
;;
2019-09-24 11:01:34 +02:00
esac
2019-09-24 13:33:15 +02:00
# 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.
#
# The " " acts as the padding between the ascii art and the text as
# it appends 3 spaces to the end of each line.
while read -r line || [ -n "$line" ]; do
ascii_height=$((ascii_height + 1))
ascii_width=$((${#line} > ascii_width ? ${#line} : ascii_width))
2019-09-24 13:59:14 +02:00
done <<-EOF
$(printf %s "$ascii" | sed 's/\[3.m//g')
EOF
2019-09-24 13:33:15 +02:00
# Add a gap between the ascii art and the information.
ascii_width=$((ascii_width + 4))
2019-09-24 11:01:34 +02:00
# Print the ascii art and position the cursor back where we
# started prior to printing it.
2019-09-24 12:52:55 +02:00
# '\033[?7l': Disable line-wrapping.
# '\033[?25l': Hide the cursor.
# '\033[1m': Print the ascii in bold.
# '\033[m': Clear bold.
# '\033[%sA: Move the cursor up '$ascii_height' amount of lines.
2019-09-24 12:52:55 +02:00
printf '\033[?7l\033[?25l\033[1m%s\033[m\033[%sA' "$ascii" "$ascii_height"
2019-09-24 11:01:34 +02:00
}
2019-09-24 09:33:23 +02:00
main() {
2019-09-24 11:26:34 +02:00
# Hide 'stderr' unless the first argument is '-v'. This saves
# polluting the script with '2>/dev/null'.
[ "$1" = -v ] || exec 2>/dev/null
2019-09-24 11:01:34 +02:00
# Generic color list.
# Disable warning about unused variables.
# shellcheck disable=2034
{
2019-09-24 12:27:33 +02:00
c1=''; c2=''
c3=''; c4=''
c5=''; c6=''
c7=''; c8=''
2019-09-24 11:01:34 +02:00
}
2019-09-24 09:33:23 +02:00
# 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.
2019-09-24 13:59:14 +02:00
read -r os kernel <<-EOF
$(uname -sr)
EOF
2019-09-24 09:33:23 +02:00
2019-09-24 13:04:43 +02:00
# 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
2019-09-24 13:41:20 +02:00
set +f ${PF_INFO-ascii title distro 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
2019-09-24 14:11:55 +02:00
command -v "get_$info" >/dev/null &&
info_length=$((${#info} > info_length ? ${#info} : info_length))
2019-09-24 13:41:20 +02:00
done
2019-09-24 13:04:43 +02:00
# Iterate over the above list and run any existing "get_" functions.
2019-09-24 13:41:20 +02:00
for info; do
"get_$info"
done
2019-09-24 13:04:43 +02:00
}
2019-09-24 11:01:34 +02:00
2019-09-24 12:32:06 +02:00
# 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, else move it down N lines.
#
2019-09-24 11:01:34 +02:00
# 'log' contains the amount of 'get_' info lines that were printed.
2019-09-24 12:32:06 +02:00
#
2019-09-24 12:52:55 +02:00
# '\033[?7h': Enable line-wrapping.
2019-09-24 12:32:06 +02:00
# '\033[%sB': Move the cursor down N lines.
# '\033[?25h': Un-hide the cursor.
2019-09-24 12:52:55 +02:00
printf '\033[?7h\033[%sB\n\033[?25h' \
2019-09-24 12:32:06 +02:00
"$((info_height > ascii_height ? 0 : ascii_height - info_height))"
2019-09-24 09:33:23 +02:00
}
main "$@"