Dotfiles for different machines on different branches.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1561 lines
49 KiB

  1. #!/bin/sh
  2. #
  3. # pfetch - Simple POSIX sh fetch script.
  4. log() {
  5. # The 'log()' function handles the printing of information.
  6. # In 'pfetch' (and 'neofetch'!) the printing of the ascii art and info
  7. # happen independently of each other.
  8. #
  9. # The size of the ascii art is stored and the ascii is printed first.
  10. # Once the ascii is printed, the cursor is located right below the art
  11. # (See marker $[1]).
  12. #
  13. # Using the stored ascii size, the cursor is then moved to marker $[2].
  14. # This is simply a cursor up escape sequence using the "height" of the
  15. # ascii art.
  16. #
  17. # 'log()' then moves the cursor to the right the "width" of the ascii art
  18. # with an additional amount of padding to add a gap between the art and
  19. # the information (See marker $[3]).
  20. #
  21. # When 'log()' has executed, the cursor is then located at marker $[4].
  22. # When 'log()' is run a second time, the next line of information is
  23. # printed, moving the cursor to marker $[5].
  24. #
  25. # Markers $[4] and $[5] repeat all the way down through the ascii art
  26. # until there is no more information left to print.
  27. #
  28. # Every time 'log()' is called the script keeps track of how many lines
  29. # were printed. When printing is complete the cursor is then manually
  30. # placed below the information and the art according to the "heights"
  31. # of both.
  32. #
  33. # The math is simple: move cursor down $((ascii_height - info_height)).
  34. # If the aim is to move the cursor from marker $[5] to marker $[6],
  35. # plus the ascii height is 8 while the info height is 2 it'd be a move
  36. # of 6 lines downwards.
  37. #
  38. # However, if the information printed is "taller" (takes up more lines)
  39. # than the ascii art, the cursor isn't moved at all!
  40. #
  41. # Once the cursor is at marker $[6], the script exits. This is the gist
  42. # of how this "dynamic" printing and layout works.
  43. #
  44. # This method allows ascii art to be stored without markers for info
  45. # and it allows for easy swapping of info order and amount.
  46. #
  47. # $[2] ___ $[3] goldie@KISS
  48. # $[4](.· | $[5] os KISS Linux
  49. # (<> |
  50. # / __ \
  51. # ( / \ /|
  52. # _/\ __)/_)
  53. # \/-____\/
  54. # $[1]
  55. #
  56. # $[6] /home/goldie $
  57. # End here if no data was found.
  58. [ "$2" ] || return
  59. # Store the value of '$1' as we reset the argument list below.
  60. name=$1
  61. # Use 'set --' as a means of stripping all leading and trailing
  62. # white-space from the info string. This also normalizes all
  63. # white-space inside of the string.
  64. #
  65. # Disable the shellcheck warning for word-splitting
  66. # as it's safe and intended ('set -f' disables globbing).
  67. # shellcheck disable=2046,2086
  68. {
  69. set -f
  70. set +f -- $2
  71. info=$*
  72. }
  73. # Move the cursor to the right, the width of the ascii art with an
  74. # additional gap for text spacing.
  75. printf '[%sC' "${ascii_width--1}"
  76. # Print the info name and color the text.
  77. printf '[3%s;1m%s' "${PF_COL1-4}" "$name"
  78. # Print the info name and info data separator.
  79. printf %s "$PF_SEP"
  80. # Move the cursor backward the length of the *current* info name and
  81. # then move it forwards the length of the *longest* info name. This
  82. # aligns each info data line.
  83. printf '[%sD[%sC' "${#name}" "${PF_ALIGN:-$info_length}"
  84. # Print the info data, color it and strip all leading whitespace
  85. # from the string.
  86. printf '[3%sm%s\n' "${PF_COL2-7}" "$info"
  87. # Keep track of the number of times 'log()' has been run.
  88. info_height=$((${info_height:-0} + 1))
  89. }
  90. get_title() {
  91. # Username is retrieved by first checking '$USER' with a fallback
  92. # to the 'id -un' command.
  93. user=${USER:-$(id -un)}
  94. # Hostname is retrieved by first checking '$HOSTNAME' with a fallback
  95. # to the 'hostname' command.
  96. #
  97. # Disable the warning about '$HOSTNAME' being undefined in POSIX sh as
  98. # the intention for using it is allowing the user to overwrite the
  99. # value on invocation.
  100. # shellcheck disable=SC2039
  101. hostname=${HOSTNAME:-${hostname:-$(hostname)}}
  102. log "[3${PF_COL3:-1}m${user}${c7}@[3${PF_COL3:-1}m${hostname}" " " >&6
  103. }
  104. get_os() {
  105. # This function is called twice, once to detect the distribution name
  106. # for the purposes of picking an ascii art early and secondly to display
  107. # the distribution name in the info output (if enabled).
  108. #
  109. # On first run, this function displays _nothing_, only on the second
  110. # invocation is 'log()' called.
  111. [ "$distro" ] && {
  112. log os "$distro" >&6
  113. return
  114. }
  115. case $os in
  116. Linux*)
  117. # Some Linux distributions (which are based on others)
  118. # fail to identify as they **do not** change the upstream
  119. # distribution's identification packages or files.
  120. #
  121. # It is senseless to add a special case in the code for
  122. # each and every distribution (which _is_ technically no
  123. # different from what it is based on) as they're either too
  124. # lazy to modify upstream's identification files or they
  125. # don't have the know-how (or means) to ship their own
  126. # lsb-release package.
  127. #
  128. # This causes users to think there's a bug in system detection
  129. # tools like neofetch or pfetch when they technically *do*
  130. # function correctly.
  131. #
  132. # Exceptions are made for distributions which are independent,
  133. # not based on another distribution or follow different
  134. # standards.
  135. #
  136. # This applies only to distributions which follow the standard
  137. # by shipping unmodified identification files and packages
  138. # from their respective upstreams.
  139. if command -v lsb_release; then
  140. distro=$(lsb_release -sd)
  141. # Android detection works by checking for the existence of
  142. # the follow two directories. I don't think there's a simpler
  143. # method than this.
  144. elif [ -d /system/app ] && [ -d /system/priv-app ]; then
  145. distro="Android $(getprop ro.build.version.release)"
  146. else
  147. # This used to be a simple '. /etc/os-release' but I believe
  148. # this is insecure as we blindly executed whatever was in the
  149. # file. This parser instead simply handles 'key=val', treating
  150. # the file contents as plain-text.
  151. while IFS='=' read -r key val; do
  152. case $key in
  153. PRETTY_NAME) distro=$val ;;
  154. esac
  155. done < /etc/os-release
  156. fi
  157. # 'os-release' and 'lsb_release' sometimes add quotes
  158. # around the distribution name, strip them.
  159. distro=${distro##[\"\']}
  160. distro=${distro%%[\"\']}
  161. # Special cases for (independent) distributions which
  162. # don't follow any os-release/lsb standards whatsoever.
  163. command -v crux && distro=$(crux)
  164. command -v guix && distro='Guix System'
  165. # Check to see if we're running Bedrock Linux which is
  166. # very unique. This simply checks to see if the user's
  167. # PATH contais a Bedrock specific value.
  168. case $PATH in
  169. */bedrock/cross/*) distro='Bedrock Linux'
  170. esac
  171. # Check to see if Linux is running in Windows 10 under
  172. # WSL1 (Windows subsystem for Linux [version 1]) and
  173. # append a string accordingly.
  174. #
  175. # If the kernel version string ends in "-Microsoft",
  176. # we're very likely running under Windows 10 in WSL1.
  177. [ "${kernel%%*-Microsoft}" ] ||
  178. distro="$distro on Windows 10 [WSL1]"
  179. # Check to see if Linux is running in Windows 10 under
  180. # WSL2 (Windows subsystem for Linux [version 2]) and
  181. # append a string accordingly.
  182. #
  183. # This checks to see if '$WSLENV' is defined. This
  184. # appends the Windows 10 string even if '$WSLENV' is
  185. # empty. We only need to check that is has been _exported_.
  186. distro="${distro}${WSLENV+ on Windows 10 [WSL2]}"
  187. ;;
  188. Darwin*)
  189. # Parse the SystemVersion.plist file to grab the macOS
  190. # version. The file is in the following format:
  191. #
  192. # <key>ProductVersion</key>
  193. # <string>10.14.6</string>
  194. #
  195. # 'IFS' is set to '<>' to enable splitting between the
  196. # keys and a second 'read' is used to operate on the
  197. # next line directly after a match.
  198. #
  199. # '_' is used to nullify a field. '_ _ line _' basically
  200. # says "populate $line with the third field's contents".
  201. while IFS='<>' read -r _ _ line _; do
  202. case $line in
  203. # Match 'ProductVersion' and read the next line
  204. # directly as it contains the key's value.
  205. ProductVersion)
  206. IFS='<>' read -r _ _ mac_version _
  207. break
  208. ;;
  209. esac
  210. done < /System/Library/CoreServices/SystemVersion.plist
  211. # Use the ProductVersion to determine which macOS/OS X codename
  212. # the system has. As far as I'm aware there's no "dynamic" way
  213. # of grabbing this information.
  214. case $mac_version in
  215. 10.4*) distro='Mac OS X Tiger' ;;
  216. 10.5*) distro='Mac OS X Leopard' ;;
  217. 10.6*) distro='Mac OS X Snow Leopard' ;;
  218. 10.7*) distro='Mac OS X Lion' ;;
  219. 10.8*) distro='OS X Mountain Lion' ;;
  220. 10.9*) distro='OS X Mavericks' ;;
  221. 10.10*) distro='OS X Yosemite' ;;
  222. 10.11*) distro='OS X El Capitan' ;;
  223. 10.12*) distro='macOS Sierra' ;;
  224. 10.13*) distro='macOS High Sierra' ;;
  225. 10.14*) distro='macOS Mojave' ;;
  226. 10.15*) distro='macOS Catalina' ;;
  227. *) distro='macOS' ;;
  228. esac
  229. distro="$distro $mac_version"
  230. ;;
  231. Haiku)
  232. # Haiku uses 'uname -v' for version information
  233. # instead of 'uname -r' which only prints '1'.
  234. distro=$(uname -sv)
  235. ;;
  236. Minix|DragonFly)
  237. distro="$os $kernel"
  238. # Minix and DragonFly don't support the escape
  239. # sequences used, clear the exit trap.
  240. trap '' EXIT
  241. ;;
  242. SunOS)
  243. # Grab the first line of the '/etc/release' file
  244. # discarding everything after '('.
  245. IFS='(' read -r distro _ < /etc/release
  246. ;;
  247. OpenBSD*)
  248. # Show the OpenBSD version type (current if present).
  249. # kern.version=OpenBSD 6.6-current (GENERIC.MP) ...
  250. IFS=' =' read -r _ distro openbsd_ver _ <<-EOF
  251. $(sysctl kern.version)
  252. EOF
  253. distro="$distro $openbsd_ver"
  254. ;;
  255. *)
  256. # Catch all to ensure '$distro' is never blank.
  257. # This also handles the BSDs.
  258. distro="$os $kernel"
  259. ;;
  260. esac
  261. }
  262. get_kernel() {
  263. case $os in
  264. # Don't print kernel output on some systems as the
  265. # OS name includes it.
  266. *BSD*|Haiku|Minix)
  267. return
  268. ;;
  269. esac
  270. # '$kernel' is the cached output of 'uname -r'.
  271. log kernel "$kernel" >&6
  272. }
  273. get_host() {
  274. case $os in
  275. Linux*)
  276. # Despite what these files are called, version doesn't
  277. # always contain the version nor does name always contain
  278. # the name.
  279. read -r name < /sys/devices/virtual/dmi/id/product_name
  280. read -r version < /sys/devices/virtual/dmi/id/product_version
  281. read -r model < /sys/firmware/devicetree/base/model
  282. host="$name $version $model"
  283. ;;
  284. Darwin*|FreeBSD*|DragonFly*)
  285. host=$(sysctl -n hw.model)
  286. ;;
  287. NetBSD*)
  288. host=$(sysctl -n machdep.dmi.system-vendor \
  289. machdep.dmi.system-product)
  290. ;;
  291. OpenBSD*)
  292. host=$(sysctl -n hw.version)
  293. ;;
  294. *BSD*|Minix)
  295. host=$(sysctl -n hw.vendor hw.product)
  296. ;;
  297. esac
  298. # Turn the host string into an argument list so we can iterate
  299. # over it and remove OEM strings and other information which
  300. # shouldn't be displayed.
  301. #
  302. # Disable the shellcheck warning for word-splitting
  303. # as it's safe and intended ('set -f' disables globbing).
  304. # shellcheck disable=2046,2086
  305. {
  306. set -f
  307. set +f -- $host
  308. host=
  309. }
  310. # Iterate over the host string word by word as a means of stripping
  311. # unwanted and OEM information from the string as a whole.
  312. #
  313. # This could have been implemented using a long 'sed' command with
  314. # a list of word replacements, however I want to show that something
  315. # like this is possible in pure sh.
  316. #
  317. # This string reconstruction is needed as some OEMs either leave the
  318. # identification information as "To be filled by OEM", "Default",
  319. # "undefined" etc and we shouldn't print this to the screen.
  320. for word; do
  321. # This works by reconstructing the string by excluding words
  322. # found in the "blacklist" below. Only non-matches are appended
  323. # to the final host string.
  324. case $word in
  325. To | [Bb]e | [Ff]illed | [Bb]y | O.E.M. | OEM |\
  326. Not | Applicable | Specified | System | Product | Name |\
  327. Version | Undefined | Default | string | INVALID | � | os )
  328. continue
  329. ;;
  330. esac
  331. host="$host$word "
  332. done
  333. # '$arch' is the cached output from 'uname -m'.
  334. log host "${host:-$arch}" >&6
  335. }
  336. get_uptime() {
  337. # Uptime works by retrieving the data in total seconds and then
  338. # converting that data into days, hours and minutes using simple
  339. # math.
  340. case $os in
  341. Linux*|Minix*)
  342. IFS=. read -r s _ < /proc/uptime
  343. ;;
  344. Darwin*|*BSD*|DragonFly*)
  345. s=$(sysctl -n kern.boottime)
  346. # Extract the uptime in seconds from the following output:
  347. # [...] { sec = 1271934886, usec = 667779 } Thu Apr 22 12:14:46 2010
  348. s=${s#*=}
  349. s=${s%,*}
  350. # The uptime format from 'sysctl' needs to be subtracted from
  351. # the current time in seconds.
  352. s=$(($(date +%s) - s))
  353. ;;
  354. Haiku)
  355. # The boot time is returned in microseconds, convert it to
  356. # regular seconds.
  357. s=$(($(system_time) / 1000000))
  358. ;;
  359. SunOS)
  360. # Split the output of 'kstat' on '.' and any white-space
  361. # which exists in the command output.
  362. #
  363. # The output is as follows:
  364. # unix:0:system_misc:snaptime 14809.906993005
  365. #
  366. # The parser extracts: ^^^^^
  367. IFS=' .' read -r _ s _ <<-EOF
  368. $(kstat -p unix:0:system_misc:snaptime)
  369. EOF
  370. ;;
  371. IRIX)
  372. # Grab the uptime in a pretty format. Usually,
  373. # 00:00:00 from the 'ps' command.
  374. t=$(LC_ALL=POSIX ps -o etime= -p 1)
  375. # Split the pretty output into days or hours
  376. # based on the uptime.
  377. case $t in
  378. *-*) d=${t%%-*} t=${t#*-} ;;
  379. *:*:*) h=${t%%:*} t=${t#*:} ;;
  380. esac
  381. h=${h#0} t=${t#0}
  382. # Convert the split pretty fields back into
  383. # seconds so we may re-convert them to our format.
  384. s=$((${d:-0}*86400 + ${h:-0}*3600 + ${t%%:*}*60 + ${t#*:}))
  385. ;;
  386. esac
  387. # Convert the uptime from seconds into days, hours and minutes.
  388. d=$((s / 60 / 60 / 24))
  389. h=$((s / 60 / 60 % 24))
  390. m=$((s / 60 % 60))
  391. # Only append days, hours and minutes if they're non-zero.
  392. [ "$d" = 0 ] || uptime="${uptime}${d}d "
  393. [ "$h" = 0 ] || uptime="${uptime}${h}h "
  394. [ "$m" = 0 ] || uptime="${uptime}${m}m "
  395. log uptime "${uptime:-0m}" >&6
  396. }
  397. get_pkgs() {
  398. # This is just a simple wrapper around 'command -v' to avoid
  399. # spamming '>/dev/null' throughout this function.
  400. has() { command -v "$1" >/dev/null; }
  401. # This works by first checking for which package managers are
  402. # installed and finally by printing each package manager's
  403. # package list with each package one per line.
  404. #
  405. # The output from this is then piped to 'wc -l' to count each
  406. # line, giving us the total package count of whatever package
  407. # managers are installed.
  408. #
  409. # Backticks are *required* here as '/bin/sh' on macOS is
  410. # 'bash 3.2' and it can't handle the following:
  411. #
  412. # var=$(
  413. # code here
  414. # )
  415. #
  416. # shellcheck disable=2006
  417. packages=`
  418. case $os in
  419. Linux*)
  420. # Commands which print packages one per line.
  421. has bonsai && bonsai list
  422. has crux && pkginfo -i
  423. has pacman-key && pacman -Qq
  424. has dpkg && dpkg-query -f '.\n' -W
  425. has rpm && rpm -qa
  426. has xbps-query && xbps-query -l
  427. has apk && apk info
  428. has guix && guix package --list-installed
  429. has opkg && opkg list-installed
  430. # Directories containing packages.
  431. has kiss && printf '%s\n' /var/db/kiss/installed/*/
  432. has brew && printf '%s\n' "$(brew --cellar)/"*
  433. has emerge && printf '%s\n' /var/db/pkg/*/*/
  434. has pkgtool && printf '%s\n' /var/log/packages/*
  435. has eopkg && printf '%s\n' /var/lib/eopkg/package/*
  436. # 'nix' requires two commands.
  437. has nix-store && {
  438. nix-store -q --requisites /run/current-system/sw
  439. nix-store -q --requisites ~.nix-profile
  440. }
  441. ;;
  442. Darwin*)
  443. # Commands which print packages one per line.
  444. has pkgin && pkgin list
  445. # Directories containing packages.
  446. has brew && printf '%s\n' /usr/local/Cellar/*
  447. # 'port' prints a single line of output to 'stdout'
  448. # when no packages are installed and exits with
  449. # success causing a false-positive of 1 package
  450. # installed.
  451. #
  452. # 'port' should really exit with a non-zero code
  453. # in this case to allow scripts to cleanly handle
  454. # this behavior.
  455. has port && {
  456. pkg_list=$(port installed)
  457. [ "$pkg_list" = "No ports are installed." ] ||
  458. printf '%s\n' "$pkg_list"
  459. }
  460. ;;
  461. FreeBSD*|DragonFly*)
  462. pkg info
  463. ;;
  464. OpenBSD*)
  465. printf '%s\n' /var/db/pkg/*/
  466. ;;
  467. NetBSD*)
  468. pkg_info
  469. ;;
  470. Haiku)
  471. printf '%s\n' /boot/system/package-links/*
  472. ;;
  473. Minix)
  474. printf '%s\n' /usr/pkg/var/db/pkg/*/
  475. ;;
  476. SunOS)
  477. has pkginfo && pkginfo -i
  478. has pkg && pkg list
  479. ;;
  480. IRIX)
  481. versions -b
  482. ;;
  483. esac | wc -l
  484. `
  485. case $os in
  486. # IRIX's package manager adds 3 lines of extra
  487. # output which we must account for here.
  488. IRIX) packages=$((packages - 3)) ;;
  489. esac
  490. [ "$packages" -gt 1 ] && log pkgs "$packages" >&6
  491. }
  492. get_memory() {
  493. case $os in
  494. # Used memory is calculated using the following "formula":
  495. # MemUsed = MemTotal + Shmem - MemFree - Buffers - Cached - SReclaimable
  496. # Source: https://github.com/KittyKatt/screenFetch/issues/386
  497. Linux*)
  498. # Parse the '/proc/meminfo' file splitting on ':' and 'k'.
  499. # The format of the file is 'key: 000kB' and an additional
  500. # split is used on 'k' to filter out 'kB'.
  501. while IFS=':k ' read -r key val _; do
  502. case $key in
  503. MemTotal)
  504. mem_used=$((mem_used + val))
  505. mem_full=$val
  506. ;;
  507. Shmem)
  508. mem_used=$((mem_used + val))
  509. ;;
  510. MemFree|Buffers|Cached|SReclaimable)
  511. mem_used=$((mem_used - val))
  512. ;;
  513. esac
  514. done < /proc/meminfo
  515. mem_used=$((mem_used / 1024))
  516. mem_full=$((mem_full / 1024))
  517. ;;
  518. # Used memory is calculated using the following "formula":
  519. # (wired + active + occupied) * 4 / 1024
  520. Darwin*)
  521. mem_full=$(($(sysctl -n hw.memsize) / 1024 / 1024))
  522. # Parse the 'vmstat' file splitting on ':' and '.'.
  523. # The format of the file is 'key: 000.' and an additional
  524. # split is used on '.' to filter it out.
  525. while IFS=:. read -r key val; do
  526. case $key in
  527. *' wired'*|*' active'*|*' occupied'*)
  528. mem_used=$((mem_used + ${val:-0}))
  529. ;;
  530. esac
  531. # Using '<<-EOF' is the only way to loop over a command's
  532. # output without the use of a pipe ('|').
  533. # This ensures that any variables defined in the while loop
  534. # are still accessible in the script.
  535. done <<-EOF
  536. $(vm_stat)
  537. EOF
  538. mem_used=$((mem_used * 4 / 1024))
  539. ;;
  540. OpenBSD*)
  541. mem_full=$(($(sysctl -n hw.physmem) / 1024 / 1024))
  542. # This is a really simpler parser for 'vmstat' which grabs
  543. # the used memory amount in a lazy way. 'vmstat' prints 3
  544. # lines of output with the needed value being stored in the
  545. # final line.
  546. #
  547. # This loop simply grabs the 3rd element of each line until
  548. # the EOF is reached. Each line overwrites the value of the
  549. # previous one so we're left with what we wanted. This isn't
  550. # slow as only 3 lines are parsed.
  551. while read -r _ _ line _; do
  552. mem_used=${line%%M}
  553. # Using '<<-EOF' is the only way to loop over a command's
  554. # output without the use of a pipe ('|').
  555. # This ensures that any variables defined in the while loop
  556. # are still accessible in the script.
  557. done <<-EOF
  558. $(vmstat)
  559. EOF
  560. ;;
  561. # Used memory is calculated using the following "formula":
  562. # mem_full - ((inactive + free + cache) * page_size / 1024)
  563. FreeBSD*|DragonFly*)
  564. mem_full=$(($(sysctl -n hw.physmem) / 1024 / 1024))
  565. # Use 'set --' to store the output of the command in the
  566. # argument list. POSIX sh has no arrays but this is close enough.
  567. #
  568. # Disable the shellcheck warning for word-splitting
  569. # as it's safe and intended ('set -f' disables globbing).
  570. # shellcheck disable=2046
  571. {
  572. set -f
  573. set +f -- $(sysctl -n hw.pagesize \
  574. vm.stats.vm.v_inactive_count \
  575. vm.stats.vm.v_free_count \
  576. vm.stats.vm.v_cache_count)
  577. }
  578. # Calculate the amount of used memory.
  579. # $1: hw.pagesize
  580. # $2: vm.stats.vm.v_inactive_count
  581. # $3: vm.stats.vm.v_free_count
  582. # $4: vm.stats.vm.v_cache_count
  583. mem_used=$((mem_full - (($2 + $3 + $4) * $1 / 1024 / 1024)))
  584. ;;
  585. NetBSD*)
  586. mem_full=$(($(sysctl -n hw.physmem64) / 1024 / 1024))
  587. # NetBSD implements a lot of the Linux '/proc' filesystem,
  588. # this uses the same parser as the Linux memory detection.
  589. while IFS=':k ' read -r key val _; do
  590. case $key in
  591. MemFree)
  592. mem_free=$((val / 1024))
  593. break
  594. ;;
  595. esac
  596. done < /proc/meminfo
  597. mem_used=$((mem_full - mem_free))
  598. ;;
  599. Haiku)
  600. # Read the first line of 'sysinfo -mem' splitting on
  601. # '(', ' ', and ')'. The needed information is then
  602. # stored in the 5th and 7th elements. Using '_' "consumes"
  603. # an element allowing us to proceed to the next one.
  604. #
  605. # The parsed format is as follows:
  606. # 3501142016 bytes free (used/max 792645632 / 4293787648)
  607. IFS='( )' read -r _ _ _ _ mem_used _ mem_full <<-EOF
  608. $(sysinfo -mem)
  609. EOF
  610. mem_used=$((mem_used / 1024 / 1024))
  611. mem_full=$((mem_full / 1024 / 1024))
  612. ;;
  613. Minix)
  614. # Minix includes the '/proc' filesystem though the format
  615. # differs from Linux. The '/proc/meminfo' file is only a
  616. # single line with space separated elements and elements
  617. # 2 and 3 contain the total and free memory numbers.
  618. read -r _ mem_full mem_free _ < /proc/meminfo
  619. mem_used=$(((mem_full - mem_free) / 1024))
  620. mem_full=$(( mem_full / 1024))
  621. ;;
  622. SunOS)
  623. hw_pagesize=$(pagesize)
  624. # 'kstat' outputs memory in the following format:
  625. # unix:0:system_pages:pagestotal 1046397
  626. # unix:0:system_pages:pagesfree 885018
  627. #
  628. # This simply uses the first "element" (white-space
  629. # separated) as the key and the second element as the
  630. # value.
  631. #
  632. # A variable is then assigned based on the key.
  633. while read -r key val; do
  634. case $key in
  635. *total) pages_full=$val ;;
  636. *free) pages_free=$val ;;
  637. esac
  638. done <<-EOF
  639. $(kstat -p unix:0:system_pages:pagestotal \
  640. unix:0:system_pages:pagesfree)
  641. EOF
  642. mem_full=$((pages_full * hw_pagesize / 1024 / 1024))
  643. mem_free=$((pages_free * hw_pagesize / 1024 / 1024))
  644. mem_used=$((mem_full - mem_free))
  645. ;;
  646. IRIX)
  647. # Read the memory information from the 'top' command. Parse
  648. # and split each line until we reach the line starting with
  649. # "Memory".
  650. #
  651. # Example output: Memory: 160M max, 147M avail, .....
  652. while IFS=' :' read -r label mem_full _ mem_free _; do
  653. case $label in
  654. Memory)
  655. mem_full=${mem_full%M}
  656. mem_free=${mem_free%M}
  657. break
  658. ;;
  659. esac
  660. done <<-EOF
  661. $(top -n)
  662. EOF
  663. mem_used=$((mem_full - mem_free))
  664. ;;
  665. esac
  666. log memory "${mem_used:-?}M / ${mem_full:-?}M" >&6
  667. }
  668. get_wm() {
  669. case $os in
  670. # Don't display window manager on macOS.
  671. Darwin*) ;;
  672. *)
  673. # xprop can be used to grab the window manager's properties
  674. # which contains the window manager's name under '_NET_WM_NAME'.
  675. #
  676. # The upside to using 'xprop' is that you don't need to hardcode
  677. # a list of known window manager names. The downside is that
  678. # not all window managers conform to setting the '_NET_WM_NAME'
  679. # atom..
  680. #
  681. # List of window managers which fail to set the name atom:
  682. # catwm, fvwm, dwm, 2bwm, monster, wmaker and sowm [mine! ;)].
  683. #
  684. # The final downside to this approach is that it does _not_
  685. # support Wayland environments. The only solution which supports
  686. # Wayland is the 'ps' parsing mentioned below.
  687. #
  688. # A more naive implementation is to parse the last line of
  689. # '~/.xinitrc' to extract the second white-space separated
  690. # element.
  691. #
  692. # The issue with an approach like this is that this line data
  693. # does not always equate to the name of the window manager and
  694. # could in theory be _anything_.
  695. #
  696. # This also fails when the user launches xorg through a display
  697. # manager or other means.
  698. #
  699. #
  700. # Another naive solution is to parse 'ps' with a hardcoded list
  701. # of window managers to detect the current window manager (based
  702. # on what is running).
  703. #
  704. # The issue with this approach is the need to hardcode and
  705. # maintain a list of known window managers.
  706. #
  707. # Another issue is that process names do not always equate to
  708. # the name of the window manager. False-positives can happen too.
  709. #
  710. # This is the only solution which supports Wayland based
  711. # environments sadly. It'd be nice if some kind of standard were
  712. # established to identify Wayland environments.
  713. #
  714. # pfetch's goal is to remain _simple_, if you'd like a "full"
  715. # implementation of window manager detection use 'neofetch'.
  716. #
  717. # Neofetch use a combination of 'xprop' and 'ps' parsing to
  718. # support all window managers (including non-conforming and
  719. # Wayland) though it's a lot more complicated!
  720. # Don't display window manager if X isn't running.
  721. [ "$DISPLAY" ] || return
  722. # This is a two pass call to xprop. One call to get the window
  723. # manager's ID and another to print its properties.
  724. command -v xprop && {
  725. # The output of the ID command is as follows:
  726. # _NET_SUPPORTING_WM_CHECK: window id # 0x400000
  727. #
  728. # To extract the ID, everything before the last space
  729. # is removed.
  730. id=$(xprop -root -notype _NET_SUPPORTING_WM_CHECK)
  731. id=${id##* }
  732. # The output of the property command is as follows:
  733. # _NAME 8t
  734. # _NET_WM_PID = 252
  735. # _NET_WM_NAME = "bspwm"
  736. # _NET_SUPPORTING_WM_CHECK: window id # 0x400000
  737. # WM_CLASS = "wm", "Bspwm"
  738. #
  739. # To extract the name, everything before '_NET_WM_NAME = \"'
  740. # is removed and everything after the next '"' is removed.
  741. wm=$(xprop -id "$id" -notype -len 25 -f _NET_WM_NAME 8t)
  742. }
  743. # Handle cases of a window manager _not_ populating the
  744. # '_NET_WM_NAME' atom. Display nothing in this case.
  745. case $wm in
  746. *'_NET_WM_NAME = '*)
  747. wm=${wm##*_NET_WM_NAME = \"}
  748. wm=${wm%%\"*}
  749. ;;
  750. *)
  751. # Fallback to checking the process list
  752. # for the select few window managers which
  753. # don't set '_NET_WM_NAME'.
  754. while read -r ps_line; do
  755. case $ps_line in
  756. *catwm*) wm=catwm ;;
  757. *fvwm*) wm=fvwm ;;
  758. *dwm*) wm=dwm ;;
  759. *2bwm*) wm=2bwm ;;
  760. *monsterwm*) wm=monsterwm ;;
  761. *wmaker*) wm='Window Maker' ;;
  762. *sowm*) wm=sowm ;;
  763. esac
  764. done <<-EOF
  765. $(ps x)
  766. EOF
  767. ;;
  768. esac
  769. ;;
  770. esac
  771. log wm "$wm" >&6
  772. }
  773. get_de() {
  774. # This only supports Xorg related desktop environments though
  775. # this is fine as knowing the desktop envrionment on Windows,
  776. # macOS etc is useless (they'll always report the same value).
  777. #
  778. # Display the value of '$XDG_CURRENT_DESKTOP', if it's empty,
  779. # display the value of '$DESKTOP_SESSION'.
  780. log de "${XDG_CURRENT_DESKTOP:-$DESKTOP_SESSION}" >&6
  781. }
  782. get_shell() {
  783. # Display the basename of the '$SHELL' environment variable.
  784. log shell "${SHELL##*/}" >&6
  785. }
  786. get_editor() {
  787. # Display the value of '$VISUAL', if it's empty, display the
  788. # value of '$EDITOR'.
  789. log editor "${VISUAL:-$EDITOR}" >&6
  790. }
  791. get_palette() {
  792. # Print the first 8 terminal colors. This uses the existing
  793. # sequences to change text color with a sequence prepended
  794. # to reverse the foreground and background colors.
  795. #
  796. # This allows us to save hardcoding a second set of sequences
  797. # for background colors.
  798. palette="$c1 $c1 $c2 $c2 $c3 $c3 $c4 $c4 $c5 $c5 $c6 $c6 "
  799. # Print the palette with a new-line before and afterwards.
  800. printf '\n' >&6
  801. log "$palette
  802. " " " >&6
  803. }
  804. get_ascii() {
  805. # This is a simple function to read the contents of
  806. # an ascii file from 'stdin'. It allows for the use
  807. # of '<<-EOF' to prevent the break in indentation in
  808. # this source code.
  809. #
  810. # This function also sets the text colors according
  811. # to the ascii color.
  812. read_ascii() {
  813. # 'PF_COL1': Set the info name color according to ascii color.
  814. # 'PF_COL3': Set the title color to some other color. ¯\_(ツ)_/¯
  815. PF_COL1=${PF_COL1:-${1:-7}}
  816. PF_COL3=${PF_COL3:-$((${1:-7}%8+1))}
  817. # POSIX sh has no 'var+=' so 'var=${var}append' is used. What's
  818. # interesting is that 'var+=' _is_ supported inside '$(())'
  819. # (arithmetic) though there's no support for 'var++/var--'.
  820. #
  821. # There is also no $'\n' to add a "literal"(?) newline to the
  822. # string. The simplest workaround being to break the line inside
  823. # the string (though this has the caveat of breaking indentation).
  824. while IFS= read -r line; do
  825. ascii="$ascii$line
  826. "
  827. done
  828. }
  829. # This checks for ascii art in the following order:
  830. # '$1': Argument given to 'get_ascii()' directly.
  831. # '$PF_ASCII': Environment variable set by user.
  832. # '$distro': The detected distribution name.
  833. # '$os': The name of the operating system/kernel.
  834. #
  835. # NOTE: Each ascii art below is indented using tabs, this
  836. # allows indentation to continue naturally despite
  837. # the use of '<<-EOF'.
  838. case ${1:-${PF_ASCII:-${distro:-$os}}} in
  839. [Aa]lpine*)
  840. read_ascii 4 <<-EOF
  841. ${c4} /\\ /\\
  842. /${c7}/ ${c4}\\ \\
  843. /${c7}/ ${c4}\\ \\
  844. /${c7}// ${c4}\\ \\
  845. ${c7}// ${c4}\\ \\
  846. ${c4}\\
  847. EOF
  848. ;;
  849. [Aa]ndroid*)
  850. read_ascii 2 <<-EOF
  851. ${c2} ;, ,;
  852. ${c2} ';,.-----.,;'
  853. ${c2} ,' ',
  854. ${c2} / O O \\
  855. ${c2}| |
  856. ${c2}'-----------------'
  857. EOF
  858. ;;
  859. [Aa]rch*)
  860. read_ascii 4 <<-EOF
  861. ${c6} /\\
  862. ${c6} / \\
  863. ${c6} /\\ \\
  864. ${c4} / \\
  865. ${c4} / ,, \\
  866. ${c4} / | | -\\
  867. ${c4} /_-'' ''-_\\
  868. EOF
  869. ;;
  870. [Aa]rco*)
  871. read_ascii 4 <<-EOF
  872. ${c4} /\\
  873. ${c4} / \\
  874. ${c4} / /\\ \\
  875. ${c4} / / \\ \\
  876. ${c4} / / \\ \\
  877. ${c4} / / _____\\ \\
  878. ${c4}/_/ \`----.\\_\\
  879. EOF
  880. ;;
  881. [Aa]rtix*)
  882. read_ascii 6 <<-EOF
  883. ${c4} /\\
  884. ${c4} / \\
  885. ${c4} /\`'.,\\
  886. ${c4} / ',
  887. ${c4} / ,\`\\
  888. ${c4} / ,.'\`. \\
  889. ${c4}/.,'\` \`'.\\
  890. EOF
  891. ;;
  892. [Bb]edrock*)
  893. read_ascii 4 <<-EOF
  894. ${c7}__
  895. ${c7}\\ \\___
  896. ${c7} \\ _ \\
  897. ${c7} \\___/
  898. EOF
  899. ;;
  900. [Cc]ent[Oo][Ss]*)
  901. read_ascii 5 <<-EOF
  902. ${c2} ____${c3}^${c5}____
  903. ${c2} |\\ ${c3}|${c5} /|
  904. ${c2} | \\ ${c3}|${c5} / |
  905. ${c5}<---- ${c4}---->
  906. ${c4} | / ${c2}|${c3} \\ |
  907. ${c4} |/__${c2}|${c3}__\\|
  908. ${c2} v
  909. EOF
  910. ;;
  911. [Dd]ebian*)
  912. read_ascii 1 <<-EOF
  913. ${c1} _____
  914. ${c1} / __ \\
  915. ${c1}| / |
  916. ${c1}| \\___-
  917. ${c1}-_
  918. ${c1} --_
  919. EOF
  920. ;;
  921. [Dd]ragon[Ff]ly*)
  922. read_ascii 1 <<-EOF
  923. ,${c1}_${c7},
  924. ('-_${c1}|${c7}_-')
  925. >--${c1}|${c7}--<
  926. (_-'${c1}|${c7}'-_)
  927. ${c1}|
  928. ${c1}|
  929. ${c1}|
  930. EOF
  931. ;;
  932. [Ee]lementary*)
  933. read_ascii <<-EOF
  934. ${c7} _______
  935. ${c7} / ____ \\
  936. ${c7}/ | / /\\
  937. ${c7}|__\\ / / |
  938. ${c7}\\ /__/ /
  939. ${c7}\\_______/
  940. EOF
  941. ;;
  942. [Ee]ndeavour*)
  943. read_ascii 4 <<-EOF
  944. ${c1}/${c4}\\
  945. ${c1}/${c4}/ \\${c6}\\
  946. ${c1}/${c4}/ \\ ${c6}\\
  947. ${c1}/ ${c4}/ _) ${c6})
  948. ${c1}/_${c4}/___-- ${c6}__-
  949. ${c6}/____--
  950. EOF
  951. ;;
  952. [Ff]edora*)
  953. read_ascii 4 <<-EOF
  954. ${c7} _____
  955. / __)${c4}\\${c7}
  956. | / ${c4}\\ \\${c7}
  957. ${c4}__${c7}_| |_${c4}_/ /${c7}
  958. ${c4}/ ${c7}(_ _)${c4}_/${c7}
  959. ${c4}/ /${c7} | |
  960. ${c4}\\ \\${c7}__/ |
  961. ${c4}\\${c7}(_____/
  962. EOF
  963. ;;
  964. [Ff]ree[Bb][Ss][Dd]*)
  965. read_ascii 1 <<-EOF
  966. ${c1}/\\,-'''''-,/\\
  967. ${c1}\\_) (_/
  968. ${c1}| |
  969. ${c1}| |
  970. ${c1}; ;
  971. ${c1}'-_____-'
  972. EOF
  973. ;;
  974. [Gg]entoo*)
  975. read_ascii 5 <<-EOF
  976. ${c5} _-----_
  977. ${c5}( \\
  978. ${c5}\\ 0 \\
  979. ${c7} \\ )
  980. ${c7} / _/
  981. ${c7}( _-
  982. ${c7}\\____-
  983. EOF
  984. ;;
  985. [Gg]uix[Ss][Dd]*|[Gg]uix*)
  986. read_ascii 3 <<-EOF
  987. ${c3}|.__ __.|
  988. ${c3}|__ \\ / __|
  989. ${c3}\\ \\ / /
  990. ${c3}\\ \\ / /
  991. ${c3}\\ \\ / /
  992. ${c3}\\ \\/ /
  993. ${c3}\\__/
  994. EOF
  995. ;;
  996. [Hh]aiku*)
  997. read_ascii 3 <<-EOF
  998. ${c3} ,^,
  999. ${c3} / \\
  1000. ${c3}*--_ ; ; _--*
  1001. ${c3}\\ '" "' /
  1002. ${c3}'. .'
  1003. ${c3}.-'" "'-.
  1004. ${c3}'-.__. .__.-'
  1005. ${c3}|_|
  1006. EOF
  1007. ;;
  1008. [Hh]yperbola*)
  1009. read_ascii <<-EOF
  1010. ${c7} |\`__.\`/
  1011. ${c7} \____/
  1012. ${c7} .--.
  1013. ${c7} / \\
  1014. ${c7} / ___ \\
  1015. ${c7}/ .\` \`.\\
  1016. ${c7}/.\` \`.\\
  1017. EOF
  1018. ;;
  1019. [Ii][Rr][Ii][Xx]*)
  1020. read_ascii 1 <<-EOF
  1021. ${c1} __
  1022. ${c1} \\ \\ __
  1023. ${c1} \\ \\ / /
  1024. ${c1} \\ v /
  1025. ${c1} / . \\
  1026. ${c1} /_/ \\ \\
  1027. ${c1} \\_\\
  1028. EOF
  1029. ;;
  1030. [Ll]inux*[Ll]ite*|[Ll]ite*)
  1031. read_ascii 3 <<-EOF
  1032. ${c3} /\\
  1033. ${c3} / \\
  1034. ${c3} / ${c7}/ ${c3}/
  1035. ${c3}> ${c7}/ ${c3}/
  1036. ${c3}\\ ${c7}\\ ${c3}\\
  1037. ${c3}\\_${c7}\\${c3}_\\
  1038. ${c7} \\
  1039. EOF
  1040. ;;
  1041. [Ll]inux*[Mm]int*|[Mm]int)
  1042. read_ascii 2 <<-EOF
  1043. ${c2} ___________
  1044. ${c2}|_ \\
  1045. ${c2}| ${c7}| _____ ${c2}|
  1046. ${c2}| ${c7}| | | | ${c2}|
  1047. ${c2}| ${c7}| | | | ${c2}|
  1048. ${c2}| ${c7}\\__${c7}___/ ${c2}|
  1049. ${c2}\\_________/
  1050. EOF
  1051. ;;
  1052. [Ll]inux*)
  1053. read_ascii 4 <<-EOF
  1054. ${c4} ___
  1055. ${c4}(${c7}.. ${c4}|
  1056. ${c4}(${c5}<> ${c4}|
  1057. ${c4}/ ${c7}__ ${c4}\\
  1058. ${c4}( ${c7}/ \\ ${c4}/|
  1059. ${c5}_${c4}/\\ ${c7}__)${c4}/${c5}_${c4})
  1060. ${c5}\/${c4}-____${c5}\/
  1061. EOF
  1062. ;;
  1063. [Mm]ac[Oo][Ss]*|[Dd]arwin*)
  1064. read_ascii 1 <<-EOF
  1065. ${c1} .:'
  1066. ${c1} _ :'_
  1067. ${c2} .'\`_\`-'_\`\`.
  1068. ${c2}:________.-'
  1069. ${c3}:_______:
  1070. ${c4} :_______\`-;
  1071. ${c5} \`._.-._.'
  1072. EOF
  1073. ;;
  1074. [Mm]ageia*)
  1075. read_ascii 2 <<-EOF
  1076. ${c6} *
  1077. ${c6} *
  1078. ${c6} **
  1079. ${c7} /\\__/\\
  1080. ${c7}/ \\
  1081. ${c7}\\ /
  1082. ${c7} \\____/
  1083. EOF
  1084. ;;
  1085. [Mm]anjaro*)
  1086. read_ascii 2 <<-EOF
  1087. ${c2}||||||||| ||||
  1088. ${c2}||||||||| ||||
  1089. ${c2}|||| ||||
  1090. ${c2}|||| |||| ||||
  1091. ${c2}|||| |||| ||||
  1092. ${c2}|||| |||| ||||
  1093. ${c2}|||| |||| ||||
  1094. EOF
  1095. ;;
  1096. [Mm]inix*)
  1097. read_ascii 4 <<-EOF
  1098. ${c4} ,, ,,
  1099. ${c4};${c7},${c4} ', ,' ${c7},${c4};
  1100. ${c4}; ${c7}',${c4} ',,' ${c7},'${c4} ;
  1101. ${c4}; ${c7}',${c4} ${c7},'${c4} ;
  1102. ${c4}; ${c7};, '' ,;${c4} ;
  1103. ${c4}; ${c7};${c4};${c7}',,'${c4};${c7};${c4} ;
  1104. ${c4}', ${c7};${c4};; ;;${c7};${c4} ,'
  1105. ${c4} '${c7};${c4}' '${c7};${c4}'
  1106. EOF
  1107. ;;
  1108. [Mm][Xx]*)
  1109. read_ascii <<-EOF
  1110. ${c7} \\\\ /
  1111. ${c7} \\\\/
  1112. ${c7} \\\\
  1113. ${c7} /\\/ \\\\
  1114. ${c7} / \\ /\\
  1115. ${c7} / \\/ \\
  1116. ${c7}/__________\\
  1117. EOF
  1118. ;;
  1119. [Nn]et[Bb][Ss][Dd]*)
  1120. read_ascii 3 <<-EOF
  1121. ${c7}\\\\${c3}\`-______,----__
  1122. ${c7} \\\\ ${c3}__,---\`_
  1123. ${c7} \\\\ ${c3}\`.____
  1124. ${c7} \\\\${c3}-______,----\`-
  1125. ${c7} \\\\
  1126. ${c7} \\\\
  1127. ${c7} \\\\
  1128. EOF
  1129. ;;
  1130. [Nn]ix[Oo][Ss]*)
  1131. read_ascii 4 <<-EOF
  1132. ${c4} \\\\ \\\\ //
  1133. ${c4} ==\\\\__\\\\/ //
  1134. ${c4} // \\\\//
  1135. ${c4}==// //==
  1136. ${c4} //\\\\___//
  1137. ${c4}// /\\\\ \\\\==
  1138. ${c4} // \\\\ \\\\
  1139. EOF
  1140. ;;
  1141. [Oo]pen[Bb][Ss][Dd]*)
  1142. read_ascii 3 <<-EOF
  1143. ${c3} _____
  1144. ${c3} \\- -/
  1145. ${c3} \\_/ \\
  1146. ${c3} | ${c7}O O${c3} |
  1147. ${c3} |_ < ) 3 )
  1148. ${c3} / \\ /
  1149. ${c3} /-_____-\\
  1150. EOF
  1151. ;;
  1152. [Oo]pen[Ss][Uu][Ss][Ee]*|[Oo]pen*SUSE*|SUSE*|suse*)
  1153. read_ascii 2 <<-EOF
  1154. ${c2} _______
  1155. ${c2}__| __ \\
  1156. ${c2} / .\\ \\
  1157. ${c2} \\__/ |
  1158. ${c2} _______|
  1159. ${c2} \\_______
  1160. ${c2}__________/
  1161. EOF
  1162. ;;
  1163. [Oo]pen[Ww]rt*)
  1164. read_ascii 1 <<-EOF
  1165. ${c1} _______
  1166. ${c1}| |.-----.-----.-----.
  1167. ${c1}| - || _ | -__| |
  1168. ${c1}|_______|| __|_____|__|__|
  1169. ${c1} ________|__| __
  1170. ${c1}| | | |.----.| |_
  1171. ${c1}| | | || _|| _|
  1172. ${c1}|________||__| |____|
  1173. EOF
  1174. ;;
  1175. [Pp]arabola*)
  1176. read_ascii 5 <<-EOF
  1177. ${c5} __ __ __ _
  1178. ${c5}.\`_//_//_/ / \`.
  1179. ${c5} / .\`
  1180. ${c5} / .\`
  1181. ${c5} /.\`
  1182. ${c5} /\`
  1183. EOF
  1184. ;;
  1185. [Pp]op!_[Oo][Ss]*)
  1186. read_ascii 6 <<-EOF
  1187. ${c6}______
  1188. ${c6}\\ _ \\ __
  1189. ${c6}\\ \\ \\ \\ / /
  1190. ${c6}\\ \\_\\ \\ / /
  1191. ${c6}\\ ___\\ /_/
  1192. ${c6} \\ \\ _
  1193. ${c6} __\\_\\__(_)_
  1194. ${c6}(___________)
  1195. EOF
  1196. ;;
  1197. [Pp]ure[Oo][Ss]*)
  1198. read_ascii <<-EOF
  1199. ${c7} _____________
  1200. ${c7}| _________ |
  1201. ${c7}| | | |
  1202. ${c7}| | | |
  1203. ${c7}| |_________| |
  1204. ${c7}|_____________|
  1205. EOF
  1206. ;;
  1207. [Ss]lackware*)
  1208. read_ascii 4 <<-EOF
  1209. ${c4} ________
  1210. ${c4} / ______|
  1211. ${c4} | |______
  1212. ${c4} \\______ \\
  1213. ${c4} ______| |
  1214. ${c4}| |________/
  1215. ${c4}|____________
  1216. EOF
  1217. ;;
  1218. [Ss]un[Oo][Ss]|[Ss]olaris*)
  1219. read_ascii 3 <<-EOF
  1220. ${c3} . .; .
  1221. ${c3} . :; :: ;: .
  1222. ${c3} .;. .. .. .;.
  1223. ${c3}.. .. .. ..
  1224. ${c3} .;, ,;.
  1225. EOF
  1226. ;;
  1227. [Uu]buntu*)
  1228. read_ascii 3 <<-EOF
  1229. ${c3} _
  1230. ${c3} ---(_)
  1231. ${c3} _/ --- \\
  1232. ${c3}(_) | |
  1233. ${c3} \\ --- _/
  1234. ${c3} ---(_)
  1235. EOF
  1236. ;;
  1237. [Vv]oid*)
  1238. read_ascii 2 <<-EOF
  1239. ${c2} _______
  1240. ${c2} _ \\______ -
  1241. ${c2}| \\ ___ \\ |
  1242. ${c2}| | / \ | |
  1243. ${c2}| | \___/ | |
  1244. ${c2}| \\______ \\_|
  1245. ${c2} -_______\\
  1246. EOF
  1247. ;;
  1248. *)
  1249. # On no match of a distribution ascii art, this function calls
  1250. # itself again, this time to look for a more generic OS related
  1251. # ascii art (KISS Linux -> Linux).
  1252. [ "$1" ] || {
  1253. get_ascii "$os"
  1254. return
  1255. }
  1256. printf 'error: %s is not currently supported.\n' "$os" >&6
  1257. printf 'error: Open an issue for support to be added.\n' >&6
  1258. exit 1
  1259. ;;
  1260. esac
  1261. # Store the "width" (longest line) and "height" (number of lines)
  1262. # of the ascii art for positioning. This script prints to the screen
  1263. # *almost* like a TUI does. It uses escape sequences to allow dynamic
  1264. # printing of the information through user configuration.
  1265. #
  1266. # Iterate over each line of the ascii art to retrieve the above
  1267. # information. The 'sed' is used to strip 'm' color codes from
  1268. # the ascii art so they don't affect the width variable.
  1269. while read -r line; do
  1270. ascii_height=$((${ascii_height:-0} + 1))
  1271. # This was a ternary operation but they aren't supported in
  1272. # Minix's shell.
  1273. [ "${#line}" -gt "${ascii_width:-0}" ] &&
  1274. ascii_width=${#line}
  1275. # Using '<<-EOF' is the only way to loop over a command's
  1276. # output without the use of a pipe ('|').
  1277. # This ensures that any variables defined in the while loop
  1278. # are still accessible in the script.
  1279. done <<-EOF
  1280. $(printf %s "$ascii" | sed 's/\[3.m//g')
  1281. EOF
  1282. # Add a gap between the ascii art and the information.
  1283. ascii_width=$((ascii_width + 4))
  1284. # Print the ascii art and position the cursor back where we
  1285. # started prior to printing it.
  1286. # '[1m': Print the ascii in bold.
  1287. # '[m': Clear bold.
  1288. # '[%sA': Move the cursor up '$ascii_height' amount of lines.
  1289. printf '%s[%sA' "$ascii" "$ascii_height" >&6
  1290. }
  1291. main() {
  1292. [ "$1" = --version ] && {
  1293. printf 'pfetch 0.7.0\n'
  1294. exit
  1295. }
  1296. # Hide 'stderr' unless the first argument is '-v'. This saves
  1297. # polluting the script with '2>/dev/null'.
  1298. [ "$1" = -v ] || exec 2>/dev/null
  1299. # Hide 'stdout' and selectively print to it using '>&6'.
  1300. # This gives full control over what it displayed on the screen.
  1301. exec 6>&1 >/dev/null
  1302. # Allow the user to execute their own script and modify or
  1303. # extend pfetch's behavior.
  1304. # shellcheck source=/dev/null
  1305. . "${PF_SOURCE:-/dev/null}" ||:
  1306. # Ensure that the 'TMPDIR' is writable as heredocs use it and
  1307. # fail without the write permission. This was found to be the
  1308. # case on Android where the temporary directory requires root.
  1309. [ -w "${TMPDIR:-/tmp}" ] || export TMPDIR=~
  1310. # Generic color list.
  1311. # Disable warning about unused variables.
  1312. # shellcheck disable=2034
  1313. {
  1314. c1=''; c2=''
  1315. c3=''; c4=''
  1316. c5=''; c6=''
  1317. c7=''; c8=''
  1318. }
  1319. # Avoid text-wrapping from wrecking the program output.
  1320. #
  1321. # Some terminals don't support these sequences, nor do they
  1322. # silently conceal them if they're printed resulting in
  1323. # partial sequences being printed to the terminal!
  1324. [ "$TERM" = dumb ] ||
  1325. [ "$TERM" = minix ] ||
  1326. [ "$TERM" = cons25 ] || {
  1327. # Disable line-wrapping.
  1328. printf '[?7l' >&6
  1329. # Enable line-wrapping again on exit.
  1330. trap 'printf [?7h >&6' EXIT
  1331. }
  1332. # Store the output of 'uname' to avoid calling it multiple times
  1333. # throughout the script. 'read <<EOF' is the simplest way of reading
  1334. # a command into a list of variables.
  1335. read -r os kernel arch <<-EOF
  1336. $(uname -srm)
  1337. EOF
  1338. # Always run 'get_os' for the purposes of detecting which ascii
  1339. # art to display.
  1340. get_os
  1341. # Allow the user to specify the order and inclusion of information
  1342. # functions through the 'PF_INFO' environment variable.
  1343. # shellcheck disable=2086
  1344. {
  1345. # Disable globbing and set the positional parameters to the
  1346. # contents of 'PF_INFO'.
  1347. set -f
  1348. set +f -- ${PF_INFO-ascii title os host kernel uptime pkgs memory}
  1349. # Iterate over the info functions to determine the lengths of the
  1350. # "info names" for output alignment. The option names and subtitles
  1351. # match 1:1 so this is thankfully simple.
  1352. for info; do
  1353. command -v "get_$info" >/dev/null || continue
  1354. # This was a ternary operation but they aren't supported in
  1355. # Minix's shell.
  1356. [ "${#info}" -gt "${info_length:-0}" ] &&
  1357. info_length=${#info}
  1358. done
  1359. # Add an additional space of length to act as a gap.
  1360. info_length=$((info_length + 1))
  1361. # Iterate over the above list and run any existing "get_" functions.
  1362. for info; do "get_$info"; done
  1363. }
  1364. # Position the cursor below both the ascii art and information lines
  1365. # according to the height of both. If the information exceeds the ascii
  1366. # art in height, don't touch the cursor (0/unset), else move it down
  1367. # N lines.
  1368. #
  1369. # This was a ternary operation but they aren't supported in Minix's shell.
  1370. [ "${info_height:-0}" -lt "${ascii_height:-0}" ] &&
  1371. cursor_pos=$((ascii_height - info_height))
  1372. # Print '$cursor_pos' amount of newlines to correctly position the
  1373. # cursor. This used to be a 'printf $(seq X X)' however 'seq' is only
  1374. # typically available (by default) on GNU based systems!
  1375. while [ "${i:=0}" -le "${cursor_pos:-0}" ]; do
  1376. printf '\n'
  1377. i=$((i + 1))
  1378. done >&6
  1379. }
  1380. main "$@"