Initial commit

This commit is contained in:
Adrian Groh 2023-02-16 16:16:19 +01:00
commit 0c9c35b971
Signed by: Gobidev
GPG Key ID: 3AA3153E98B0D771
11 changed files with 3074 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
# Generated by Cargo
# will have compiled files and executables
debug/
target/
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

1251
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

26
Cargo.toml Normal file
View File

@ -0,0 +1,26 @@
[workspace]
members = ["pfetch-extractor"]
[package]
name = "pfetch"
version = "0.1.0"
edition = "2021"
authors = ["Gobidev"]
description = "A rewrite of the pfetch system information tool"
repository = "https://github.com/Gobidev/pfetch-rs"
license = "MIT"
keywords = ["fetch", "pfetch", "cli", "system"]
categories = ["command-line-utilities"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
pfetch-extractor = { path = "./pfetch-extractor" }
globset = "0.4.10"
dotenv = "0.15.0"
glob = "0.3.1"
which = "4.4.0"
libmacchina = "6"
[profile.release]
strip = true

19
LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2023 Adrian Groh
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

149
README.md Normal file
View File

@ -0,0 +1,149 @@
<h1 align="center">pfetch-rs</h1>
<p align="center">A rewrite of the pfetch system information tool by dylanaraps in Rust</p><br>
<p align="center"><img src="https://user-images.githubusercontent.com/50576978/219375863-579c495d-8db8-4aa9-a4a6-348ecb2c849f.png" width="350px"></p>
## About
If you are familiar with the [pfetch](https://github.com/dylanaraps/pfetch)
system information tool by [dylanaraps](https://github.com/dylanaraps), this
does the exact same thing, but with an about _10x faster_ runtime. _pfetch_ is
simple by design with some (but not many) configuration options and a
minimalistic look.
**Supported Platforms:** Linux, Android, DragonflyBSD, FreeBSD, NetBSD, OpenBSD,
WSL, Haiku, MacOS, Minix, Solaris, IRIX, SerenityOS
_Disclaimer: Aside from Linux, all of these platforms are untested. If you run
into problems, please open an issue._
**Included Logos:** Alpine Linux, Android, Arch Linux, ArcoLinux, Artix Linux,
Bedrock Linux, Buildroot, CelOS, CentOS, Crystal Linux, dahliaOS, Debian,
Devuan, DragonflyBSD, Elementary OS, EndeavourOS, Fedora, FreeBSD, Garuda Linux,
Gentoo Linux, Gnu, Guix, Haiku, HydroOS, Hyperbola, instantOS, IRIX, KDE neon,
Linux Lite, Linux, Mint, macOS, Mageia, Manjaro, Minix, MX Linux, NetBSD, NixOS,
OpenBSD, openSUSE Tumbleweed, openSUSE Leap, OpenWrt, Parabola, Pop!\_OS
(updated), PureOS, Raspbian, SerenityOS, Slackware, Solus, Solaris, Ubuntu, Void
Linux, Xeonix Linux, Fiwix (new), MorphOS (new), AmogOS (new), Aperio (new)
For all other distributions, a penguin will be displayed.
_Credit to [the original pfetch](https://github.com/dylanaraps/pfetch) and
[its contributors](https://github.com/dylanaraps/pfetch/graphs/contributors)._
If you want to add a logo, feel free to make a Pull Request.
## Status
This project is still in early development, expect things to not work properly.
Please open issues for bugs you are encountering.
## Installation
### Cargo
```sh
cargo install pfetch
```
## Performance
Benchmarks performed on an AMD Ryzen 5 3600. Execution time is measured using
[hyperfine](https://github.com/sharkdp/hyperfine) with `-w 4 -m 500 -N` flags
| Implementation | Mean [ms] | Min [ms] | Max [ms] |
| :---------------: | :--------: | :------: | :------: |
| POSIX `sh` (bash) | 27.3 ± 0.9 | 25.3 | 23.2 |
| POSIX `sh` (dash) | 19.3 ± 0.6 | 18.3 | 24.0 |
| Rust | 2.1 ± 0.2 | 1.8 | 3.6 |
_Note: This is with `pacman` being the only installed package manager.
Especially having `nix` installed will have a big impact on performance, as
querying installed `nix` packages is very costly._
## Configuration
Like the original `pfetch`, `pfetch-rs` is configured through environment
variables. Your existing config will probably still work, the only difference is
how padding is configured.
If you want to display a custom logo, you will have to download the source code,
make your changes to `./pfetch-extractor/logos.sh` and build the binary with
`cargo b --release`.
```sh
# Which information to display.
# Default: first example below
# Valid: space separated string
#
# OFF by default: shell editor wm de palette
PF_INFO="ascii title os host kernel uptime pkgs memory"
# Example: Only ASCII.
PF_INFO="ascii"
# Example: Only Information.
PF_INFO="title os host kernel uptime pkgs memory"
# A file containing environment variables to source before running pfetch.
# Default: unset
# Valid: A shell script
PF_SOURCE=""
# Separator between info name and info data.
# Default: unset
# Valid: string
PF_SEP=":"
# Enable/Disable colors in output:
# Default: 1
# Valid: 1 (enabled), 0 (disabled)
PF_COLOR=1
# Color of info names:
# Default: unset (auto)
# Valid: 0-9
PF_COL1=4
# Color of info data:
# Default: unset (auto)
# Valid: 0-9
PF_COL2=9
# Color of title data:
# Default: unset (auto)
# Valid: 0-9
PF_COL3=1
# Alignment paddings (this is different to the original version).
# Default: unset (auto)
# Valid: int
PF_PAD1=""
PF_PAD2=""
PF_PAD3=""
# Which ascii art to use.
# Default: unset (auto)
# Valid: string
PF_ASCII="openbsd"
# The below environment variables control more
# than just 'pfetch' and can be passed using
# 'HOSTNAME=cool_pc pfetch' to restrict their
# usage solely to 'pfetch'.
# Which user to display.
USER=""
# Which hostname to display.
HOSTNAME=""
# Which editor to display.
EDITOR=""
# Which shell to display.
SHELL=""
# Which desktop environment to display.
XDG_CURRENT_DESKTOP=""
```

View File

@ -0,0 +1,15 @@
[package]
name = "pfetch-extractor"
version = "0.1.0"
edition = "2021"
authors = ["Gobidev"]
[lib]
proc-macro = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
proc-macro2 = "1.0.50"
quote = "1.0.23"
regex = "1.7.1"

709
pfetch-extractor/logos.sh Normal file
View File

@ -0,0 +1,709 @@
#!/bin/bash
# Most of the below logos are from pfetch by Dylan Araps licensed under the MIT License
# The MIT License (MIT)
# Copyright (c) 2016-2019 Dylan Araps
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
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]el[Oo][Ss]*)
read_ascii 5 <<- EOF
${c5} .////\\\\\//\\.
${c5} //_ \\\\
${c5} /_ ${c7}##############
${c5} // *\\
${c7}############### ${c5}|#
${c5} \/ */
${c5} \* ${c7}##############
${c5} */, .//
${c5} '_///\\\\\//_'
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
;;
[Cc]rystal*[Ll]inux)
read_ascii 5 <<- EOF
${c5} -//.
${c5} -//.
${c5} -//. .
${c5} -//. '//-
${c5} /+: :+/
${c5} .//' .//.
${c5} . .//.
${c5} .//.
${c5} .//.
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]evuan*)
read_ascii 6 <<- EOF
${c4} ..:::.
${c4} ..-==-
${c4} .+#:
${c4} =@@
${c4} :+%@#:
${c4}.:=+#@@%*:
${c4}#@@@#=:
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* | [Nn]obara*)
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]aruda*)
read_ascii 4 <<- EOF
${c3} _______
${c3} __/ \\_
${c3} _/ / \\_
${c7} _/ /_________\\
${c7}_/ |
${c2}\\ ____________
${c2} \\_ __/
${c2} \\__________/
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
${c7} |
${c7} | |
${c7} |
${c7} | ________
${c7} | /\\ | \\
${c7} / \\ | \\ |
${c7} / \\ \\ |
${c7} / \\________\\
${c7} \\ / /
${c7} \\ / /
${c7} \\ / /
${c7} \\/________/
EOF
;;
[Ii]nstant[Oo][Ss]*)
read_ascii <<- EOF
${c7} ,-''-,
${c7}: .''. :
${c7}: ',,' :
${c7} '-____:__
${c7} : \`.
${c7} \`._.'
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} //${c7}76767${c6}//////
${c6} //${c7}76${c6}//${c7}76${c6}//${c7}767${c6}//
${c6} ////${c7}7676'${c6}//${c7}76${c6}////
${c6} /////${c7}76${c6}////${c7}7${c6}/////
${c6} /////${c7}76${c6}//${c7}76${c6}////
${c6} ///${c7}76767676${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]erenity[Oo][Ss]*)
read_ascii 4 <<- EOF
${c7} _____
${c1} ,-${c7} -,
${c1} ;${c7} ( ;
${c1}| ${c7}. \_${c1}.,${c7} |
${c1}| ${c7}o _${c1} ',${c7} |
${c1} ; ${c7}(_)${c1} )${c7} ;
${c1} '-_____-${c7}'
EOF
;;
[Ss]lackware*)
read_ascii 4 <<- EOF
${c4} ________
${c4} / ______|
${c4} | |______
${c4} \\______ \\
${c4} ______| |
${c4}| |________/
${c4}|____________
EOF
;;
[Ss]olus*)
read_ascii 4 <<- EOF
${c6}
${c6} /|
${c6} / |\\
${c6} / | \\ _
${c6} /___|__\\_\\
${c6} \\ /
${c6} \`-------´
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
;;
[Ff]iwix*)
read_ascii 12 <<- EOF
${c6}_____ ${c4}_____
${c6}\\ \\ ${c4}\\ \\
${c6}\\ \\ ${c4}\\ \\
${c6}/ \\ \\ ${c4}\\ \\
${c6}( \\ \\ ${c4}\\ \\
${c6}( / / ${c4}/ /
${c6}\\ / / ${c4}/ /
${c6}/ / ${c4}/ /
${c6}/____/ ${c4}/____/
EOF
;;
[Mm]orphOS*)
read_ascii 1 <<- EOF
${c4} __ \/ __
${c4} /o \{}/ o\\
${c4} \ () /
${c4} \`> /\ <\`
${c4} (o/\/\o)
${c4} ) (
EOF
;;
[Aa]mog[Oo][Ss]*)
read_ascii 4 <<- EOF
${c7} -///:.
${c7} smhhhhmh\`
${c7} :NA${c4}mogO${c7}SNs
${c7} hNNmmmmNNN
${c7} NNNNNNNNNN
${c7} :NNNNNNNNNN
${c7} mNNssussNNN
${c7} sNn: sNNo
${c7}+ooo+ sNNo
${c7} +oooo\`
EOF
;;
esac

105
pfetch-extractor/src/lib.rs Normal file
View File

@ -0,0 +1,105 @@
use proc_macro::TokenStream;
use quote::quote;
use regex::Regex;
#[proc_macro]
pub fn parse_logos(_input: TokenStream) -> TokenStream {
let raw_logos = include_str!("../logos.sh");
let raw_logos = raw_logos
.split_once("in\n")
.expect("Invalid logos.sh file")
.1;
let raw_logos = raw_logos
.split_once("\nesac")
.expect("Invalid logos.sh file")
.0;
let mut tux = None;
let logos = raw_logos
.split(";;\n")
.filter_map(|raw_logo| {
let (is_tux, logo) = parse_logo(raw_logo)?;
if is_tux {
tux = Some(logo.clone());
}
Some(logo)
})
.collect::<Vec<_>>();
let tux = tux.unwrap();
quote! { (#tux, [#(#logos),*]) }.into()
}
fn parse_logo(input: &str) -> Option<(bool, proc_macro2::TokenStream)> {
let input = input.trim().replace('\t', "");
if input.is_empty() {
return None;
}
let regex = Regex::new(r"^\(?(.*)\)[\s\S]*read_ascii *(\d)? *(\d)?").unwrap();
let groups = regex
.captures(&input)
.expect("Error while parsing logos.sh");
let pattern = &groups[1];
let primary_color = match groups.get(2) {
Some(color) => color.as_str().parse::<u8>().unwrap(),
None => 7,
};
let secondary_color = match groups.get(3) {
Some(color) => color.as_str().parse::<u8>().unwrap(),
None => (primary_color + 1) % 8,
};
let logo = input
.split_once("EOF\n")
.expect("Could not find start of logo")
.1
.split_once("\nEOF")
.expect("Could not find end of logo")
.0;
let mut logo_parts = vec![];
for logo_part in logo.split("${") {
if let Some((new_color, rest)) = logo_part.split_once('}') {
let new_color: u8 = match new_color {
"c0" => 0,
"c1" => 1,
"c2" => 2,
"c3" => 3,
"c4" => 4,
"c5" => 5,
"c6" => 6,
"c7" => 7,
_ => panic!("Unknown color: {new_color}"),
};
let rest = rest.replace("\\\\", "\\");
let rest = rest.replace("\\`", "`");
let lines = rest.split('\n').collect::<Vec<_>>();
let last_index = lines.len() - 1;
for (index, line) in lines.into_iter().enumerate() {
let mut line = line.to_owned();
if index != last_index {
line += "\n";
}
logo_parts.push(quote! { (Color(#new_color), #line) });
}
} else if !logo_part.is_empty() {
let logo_part = logo_part.replace("\\\\", "\\");
logo_parts.push(quote! { (Color(9), #logo_part) });
}
}
Some((
pattern == "[Ll]inux*",
quote! {
Logo {
primary_color: Color(#primary_color),
secondary_color: Color(#secondary_color),
pattern: #pattern,
logo_parts: &[#(#logo_parts),*],
}
},
))
}

66
print_all.sh Executable file
View File

@ -0,0 +1,66 @@
#!/bin/bash
# A small script to run pfetch (command specified with arguments) with all available logos
while read -r logo; do
PF_ASCII=$logo "$@"
done << EOF
alpine
android
arch
arco
artix
bedrock
buildroot
celos
centos
crystallinux
dahlia
debian
devuan
dragonfly
elementary
endeavour
fedora
freebsd
garuda
gentoo
gnu
guix
haiku
hydroOS
hyperbola
iglunix
instantos
irix
kdeneon
linuxlite
linuxmint
linux
macos
mageia
manjaro
minix
mx
netbsd
nixos
openbsd
opensusetumbleweed
opensuse
openwrt
parabola
pop!_os
pureos
raspbian
serenityos
slackware
solus
solaris
ubuntu
void
xeonix
fiwix
morphos
amogos
aperio
EOF

440
src/lib.rs Normal file
View File

@ -0,0 +1,440 @@
use std::{env, fmt::Display, fs, io::Result, process::Command, str::FromStr};
use glob::glob;
use globset::Glob;
use libmacchina::{
traits::GeneralReadout as _, traits::KernelReadout as _, traits::MemoryReadout as _,
traits::PackageReadout as _, GeneralReadout, KernelReadout, MemoryReadout, PackageReadout,
};
use pfetch_extractor::parse_logos;
#[derive(Clone, Copy)]
pub struct Color(pub u8);
impl Display for Color {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "\x1b[3{}m", self.0)
}
}
impl FromStr for Color {
type Err = String;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s.parse::<u8>() {
Ok(color) => {
if color >= 9 {
Err(format!("Invalid color: {color}"))
} else {
Ok(Color(color))
}
}
Err(_) => Err(format!("Not a valid color: {s}")),
}
}
}
pub struct Logo {
pub primary_color: Color,
pub secondary_color: Color,
pub pattern: &'static str,
pub logo_parts: &'static [(Color, &'static str)],
}
impl Display for Logo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
self.logo_parts
.iter()
.map(|(color, part)| format!("{color}{part}"))
.collect::<String>()
)
}
}
#[derive(Debug)]
pub enum PackageManager {
Pacman,
Dpkg,
Xbps,
Apk,
Rpm,
Flatpak,
Crux,
Guix,
Opkg,
Kiss,
Portage,
Pkgtool,
Nix,
}
/// Obtain the amount of installed packages on the system by checking all installed supported package
/// managers and adding the amounts
pub fn total_packages(package_readout: &PackageReadout) -> usize {
match env::consts::OS {
"linux" => {
let macchina_package_count: Vec<(String, usize)> = package_readout
.count_pkgs()
.iter()
.map(|(macchina_manager, count)| (macchina_manager.to_string(), *count))
.collect();
[
PackageManager::Pacman,
PackageManager::Dpkg,
PackageManager::Xbps,
PackageManager::Apk,
PackageManager::Rpm,
PackageManager::Flatpak,
PackageManager::Crux,
PackageManager::Guix,
PackageManager::Opkg,
PackageManager::Kiss,
PackageManager::Portage,
PackageManager::Pkgtool,
PackageManager::Nix,
]
.iter()
.map(|mngr| packages(mngr, &macchina_package_count))
.sum()
}
"macos" => {
// pkgin
run_and_count_lines("pkgin", &["list"])
// dpkg
+ run_and_count_lines("dpkg-query", &["-f", "'.\n'", "-W"])
// brew
+ if check_if_command_exists("brew") {
match glob("/usr/local/Cellar/*") {
Ok(files) => files.count(),
Err(_) => 0,
}
} else {
0
}
// port
+ match run_system_command("port", &["installed"]) {
Ok(output) => {
// port prints a single line to stdout when no packages are installed
if output == "No ports are installed." {
0
} else {
output.lines().count()
}
},
Err(_) => 0,
}
}
"freebsd" | "dragonfly" => run_and_count_lines("pkg", &["info"]),
"openbsd" => match glob("/var/db/pkg/*/") {
Ok(files) => files.count(),
Err(_) => 0,
},
"netbsd" => run_and_count_lines("pkg_info", &[]),
"solaris" => {
run_and_count_lines("pkginfo", &["-i"]) + run_and_count_lines("pkg", &["list"])
}
_ => 0,
}
}
fn get_macchina_package_count(
macchina_result: &[(String, usize)],
package_manager_name: &str,
) -> Option<usize> {
macchina_result
.iter()
.find(|entry| entry.0 == package_manager_name)
.map(|entry| entry.1)
}
/// return the amount of packages installed with a given linux package manager
/// Return `0` if the package manager is not installed
fn packages(pkg_manager: &PackageManager, macchina_package_count: &[(String, usize)]) -> usize {
match pkg_manager {
// libmacchina has very fast implementations for most package managers, so we use them
// where we can, otherwise we fall back to method used by dylans version of pfetch
PackageManager::Pacman
| PackageManager::Flatpak
| PackageManager::Dpkg
| PackageManager::Xbps
| PackageManager::Apk
| PackageManager::Rpm
| PackageManager::Portage
| PackageManager::Opkg => get_macchina_package_count(
macchina_package_count,
&format!("{pkg_manager:?}").to_lowercase(),
)
.unwrap_or(0),
PackageManager::Guix => run_and_count_lines("guix", &["package", "--list-installed"]),
PackageManager::Crux => {
if check_if_command_exists("crux") {
run_and_count_lines("pkginfo", &["-i"])
} else {
0
}
}
PackageManager::Kiss => {
if check_if_command_exists("kiss") {
match glob("/var/db/kiss/installed/*/") {
Ok(files) => files.count(),
Err(_) => 0,
}
} else {
0
}
}
PackageManager::Pkgtool => {
if check_if_command_exists("pkgtool") {
match glob("/var/log/packages/*") {
Ok(files) => files.count(),
Err(_) => 0,
}
} else {
0
}
}
// TODO: nix -q is very slow
PackageManager::Nix => {
if check_if_command_exists("nix-store") {
run_and_count_lines(
"nix-store",
&["-q", "--requisites", "/run/current-system/sw"],
) + run_and_count_lines(
"nix-store",
&[
"-q",
"--requisites",
&format!("{}/.nix-profile", env::var("HOME").unwrap_or_default()),
],
)
} else {
0
}
}
}
}
pub fn user_at_hostname(
general_readout: &GeneralReadout,
username_override: &Option<String>,
hostname_override: &Option<String>,
) -> Option<String> {
let username = match username_override {
Some(username) => Ok(username.to_string()),
None => general_readout.username(),
};
let hostname = match hostname_override {
Some(hostname) => Ok(hostname.to_string()),
None => general_readout.hostname(),
};
if username.is_err() || hostname.is_err() {
None
} else {
Some(format!(
"{}@{}",
username.unwrap_or_default(),
hostname.unwrap_or_default()
))
}
}
pub fn memory(memory_readout: &MemoryReadout) -> Option<String> {
let total_memory = memory_readout.total();
let used_memory = memory_readout.used();
if total_memory.is_err() || used_memory.is_err() {
None
} else {
Some(format!(
"{}M / {}M",
used_memory.unwrap() / 1024,
total_memory.unwrap() / 1024
))
}
}
pub fn os(general_readout: &GeneralReadout) -> Option<String> {
match general_readout.distribution() {
Ok(distribution) => Some(distribution),
Err(_) => None,
}
}
pub fn kernel(kernel_readout: &KernelReadout) -> Option<String> {
match kernel_readout.os_release() {
Ok(kernel_version) => Some(kernel_version),
Err(_) => None,
}
}
fn seconds_to_string(time: usize) -> String {
let days = if time > 86400 {
let days_pre = time / 60 / 60 / 24;
days_pre.to_string() + "d"
} else {
"".to_string()
};
let hours = if time > 3600 {
let hours_pre = (time / 60 / 60) % 24;
hours_pre.to_string() + "h"
} else {
"".to_string()
};
let minutes = if time > 60 {
let minutes_pre = (time / 60) % 60;
minutes_pre.to_string() + "m"
} else {
"0m".to_string()
};
format!("{days} {hours} {minutes}").trim_start().to_owned()
}
pub fn uptime(general_readout: &GeneralReadout) -> Option<String> {
match general_readout.uptime() {
Ok(uptime) => Some(seconds_to_string(uptime)),
Err(_) => None,
}
}
pub fn host() -> Option<String> {
const BLACKLIST: &[&str] = &[
"To",
"Be",
"be",
"Filled",
"filled",
"By",
"by",
"O.E.M.",
"OEM",
"Not",
"Applicable",
"Specified",
"System",
"Product",
"Name",
"Version",
"Undefined",
"Default",
"string",
"INVALID",
"<EFBFBD>",
"os",
"Type1ProductConfigId",
"",
];
// get device from system files
let product_name =
fs::read_to_string("/sys/devices/virtual/dmi/id/product_name").unwrap_or_default();
let product_name = product_name.trim();
let product_version =
fs::read_to_string("/sys/devices/virtual/dmi/id/product_version").unwrap_or_default();
let product_version = product_version.trim();
let product_model =
fs::read_to_string("/sys/firmware/devicetree/base/model").unwrap_or_default();
let product_model = product_model.trim();
let final_str = format!("{product_name} {product_version} {product_model}")
.split(' ')
.filter(|word| !BLACKLIST.contains(word))
.collect::<Vec<_>>()
.join(" ");
// if string is empty, display system architecture instead
let final_str = if final_str.is_empty() {
run_system_command("uname", &["-m"]).unwrap_or("Unknown".to_owned())
} else {
final_str
};
if final_str.is_empty() {
None
} else {
Some(final_str)
}
}
pub fn logo(logo_name: &str) -> Logo {
let (tux, logos) = parse_logos!();
logos
.into_iter()
.find(|logo| {
logo.pattern.split('|').any(|glob| {
Glob::new(glob.trim())
.expect("Invalid logo pattern")
.compile_matcher()
.is_match(logo_name)
})
})
.unwrap_or(tux)
}
pub fn shell(general_readout: &GeneralReadout) -> Option<String> {
match general_readout.shell(
libmacchina::traits::ShellFormat::Relative,
libmacchina::traits::ShellKind::Default,
) {
Ok(shell) => Some(shell),
Err(_) => None,
}
}
pub fn editor() -> Option<String> {
match env::var("VISUAL") {
Ok(editor) => Some(editor.trim().to_owned()),
Err(_) => match env::var("EDITOR") {
Ok(editor) => Some(editor.trim().to_owned()),
Err(_) => None,
},
}
}
pub fn wm(general_readout: &GeneralReadout) -> Option<String> {
match general_readout.window_manager() {
Ok(wm) => Some(wm),
Err(_) => None,
}
}
pub fn de(general_readout: &GeneralReadout) -> Option<String> {
match general_readout.desktop_environment() {
Ok(de) => Some(de),
Err(_) => None,
}
}
pub fn palette() -> String {
(1..7)
.map(|num| format!("\x1b[4{num}m "))
.collect::<String>()
+ "\x1b[0m"
}
fn run_system_command(command: &str, args: &[&str]) -> Result<String> {
let mut output =
String::from_utf8_lossy(&Command::new(command).args(args).output()?.stdout).into_owned();
output.truncate(output.trim_end().len());
Ok(output)
}
fn check_if_command_exists(command: &str) -> bool {
which::which(command).is_ok()
}
fn _system_command_error(command: &str, args: &[&str]) -> Result<String> {
let mut output =
String::from_utf8_lossy(&Command::new(command).args(args).output()?.stderr).into_owned();
output.truncate(output.trim_end().len());
Ok(output)
}
/// Return the amount of line the output of a system command produces
/// Returns `0` if command fails
fn run_and_count_lines(command: &str, args: &[&str]) -> usize {
run_system_command(command, args)
.unwrap_or_default()
.lines()
.count()
}

284
src/main.rs Normal file
View File

@ -0,0 +1,284 @@
use libmacchina::{
traits::GeneralReadout as _, traits::KernelReadout as _, traits::MemoryReadout as _,
traits::PackageReadout as _, GeneralReadout, KernelReadout, MemoryReadout, PackageReadout,
};
use std::{env, fmt::Display, str::FromStr};
#[derive(Debug, PartialEq)]
enum PfetchInfo {
Ascii,
Title,
Os,
Host,
Kernel,
Uptime,
Pkgs,
Memory,
Shell,
Editor,
Wm,
De,
Palette,
BlankLine,
}
impl Display for PfetchInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", format!("{self:?}").to_lowercase())
}
}
impl FromStr for PfetchInfo {
type Err = String;
fn from_str(info: &str) -> Result<Self, Self::Err> {
match info {
"ascii" => Ok(PfetchInfo::Ascii),
"title" => Ok(PfetchInfo::Title),
"os" => Ok(PfetchInfo::Os),
"host" => Ok(PfetchInfo::Host),
"kernel" => Ok(PfetchInfo::Kernel),
"uptime" => Ok(PfetchInfo::Uptime),
"pkgs" => Ok(PfetchInfo::Pkgs),
"memory" => Ok(PfetchInfo::Memory),
"shell" => Ok(PfetchInfo::Shell),
"editor" => Ok(PfetchInfo::Editor),
"wm" => Ok(PfetchInfo::Wm),
"de" => Ok(PfetchInfo::De),
"palette" => Ok(PfetchInfo::Palette),
unknown_info => Err(format!("Unknown pfetch info: {unknown_info}")),
}
}
}
fn pfetch(info: Vec<(pfetch::Color, String, String)>, logo: pfetch::Logo, logo_enabled: bool) {
let raw_logo = if logo_enabled {
logo.logo_parts
.iter()
.map(|(_, part)| *part)
.collect::<String>()
} else {
"".to_string()
};
let logo = logo.to_string();
let mut logo_lines = logo.lines();
let raw_logo_lines: Vec<_> = raw_logo.lines().collect();
let logo_width = raw_logo_lines
.iter()
.map(|line| line.chars().count())
.max()
.unwrap_or(0);
let line_amount = usize::max(raw_logo_lines.len(), info.len());
let info1_width = info
.iter()
.skip(1)
.map(|(_, line, _)| {
if line.starts_with("\x1b[4") {
0
} else {
line.len()
}
})
.max()
.unwrap_or(0);
let padding1 = match dotenv::var("PF_PAD1") {
Ok(padding0) => padding0.parse::<usize>().unwrap_or(0),
Err(_) => 0,
};
let padding2 = match dotenv::var("PF_PAD2") {
Ok(padding1) => padding1.parse::<usize>().unwrap_or(0),
Err(_) => 3,
};
let padding3 = match dotenv::var("PF_PAD3") {
Ok(padding2) => padding2.parse::<usize>().unwrap_or(0),
Err(_) => 1,
};
let mut pfetch_str = String::new();
for l in 0..line_amount {
pfetch_str += &format!(
"{padding1}\x1b[1m{logo}{padding2}{color}{info1}\x1b[0m{separator}{padding3}{color2}{info2}\n",
padding1 = " ".repeat(padding1),
logo = if logo_enabled {
logo_lines.next().unwrap_or("")
} else {
""
},
padding2 = " ".repeat(
logo_width - raw_logo_lines.get(l).map_or(0, |line| line.chars().count())
+ if logo_enabled { padding2 } else { 0 }
),
color = info.get(l).map_or("".to_owned(), |line| line.0.to_string()),
info1 = info.get(l).map_or("", |line| &line.1),
separator = info.get(l).map_or("".to_string(), |line|
if ! &line.2.is_empty() {
dotenv::var("PF_SEP").unwrap_or_default()
} else { "".to_string() }
),
padding3 = " ".repeat(
info1_width.saturating_sub(info.get(l).map_or(0, |(_, line, _)| line.len()))
+ padding3
),
color2 = match dotenv::var("PF_COL2") {
Ok(newcolor) => {
match pfetch::Color::from_str(&newcolor) {
Ok(newcolor) => format!("{newcolor}"),
Err(_) => "".to_string(),
}
},
Err(_) => "".to_string()
},
info2 = info.get(l).map_or("", |line| &line.2)
)
}
// if colors are disabled, remove them from string
if dotenv::var("PF_COLOR").unwrap_or_default() == "0" {
pfetch_str = pfetch_str
.split("\x1b[")
.map(|chunk| chunk.chars().skip(3).collect::<String>())
.collect();
}
println!("{pfetch_str}");
}
struct Readouts {
general_readout: GeneralReadout,
package_readout: PackageReadout,
memory_readout: MemoryReadout,
kernel_readout: KernelReadout,
}
fn get_info(info: &PfetchInfo, readouts: &Readouts) -> Option<String> {
match info {
PfetchInfo::Ascii => None,
PfetchInfo::Title => {
let hostname_override = match dotenv::var("HOSTNAME") {
Ok(hostname) => Some(hostname),
Err(_) => None,
};
let username_override = match dotenv::var("USER") {
Ok(username) => Some(username),
Err(_) => None,
};
pfetch::user_at_hostname(
&readouts.general_readout,
&username_override,
&hostname_override,
)
}
PfetchInfo::Os => pfetch::os(&readouts.general_readout),
PfetchInfo::Host => pfetch::host(),
PfetchInfo::Kernel => pfetch::kernel(&readouts.kernel_readout),
PfetchInfo::Uptime => pfetch::uptime(&readouts.general_readout),
PfetchInfo::Pkgs => Some(pfetch::total_packages(&readouts.package_readout).to_string()),
PfetchInfo::Memory => pfetch::memory(&readouts.memory_readout),
PfetchInfo::Shell => match dotenv::var("SHELL") {
Ok(shell) => Some(shell),
Err(_) => pfetch::shell(&readouts.general_readout),
},
PfetchInfo::Editor => match dotenv::var("EDITOR") {
Ok(editor) => Some(editor),
Err(_) => pfetch::editor(),
},
PfetchInfo::Wm => pfetch::wm(&readouts.general_readout),
PfetchInfo::De => match dotenv::var("XDG_CURRENT_DESKTOP") {
Ok(de) => Some(de),
Err(_) => pfetch::de(&readouts.general_readout),
},
PfetchInfo::Palette => Some(pfetch::palette()),
PfetchInfo::BlankLine => Some("".to_string()),
}
}
fn main() {
// source file specified by env: PF_SOURCE
if let Ok(filepath) = dotenv::var("PF_SOURCE") {
dotenv::from_path(filepath).unwrap();
}
let enabled_pf_info_base: Vec<PfetchInfo> = match dotenv::var("PF_INFO") {
Ok(pfetch_infos) => pfetch_infos
.trim()
.split(' ')
.map(|info| PfetchInfo::from_str(info).unwrap())
.collect(),
Err(_) => vec![
PfetchInfo::Ascii,
PfetchInfo::Title,
PfetchInfo::Os,
PfetchInfo::Host,
PfetchInfo::Kernel,
PfetchInfo::Uptime,
PfetchInfo::Pkgs,
PfetchInfo::Memory,
],
};
// insert blank lines before and after palettes
let mut enabled_pf_info: Vec<PfetchInfo> = vec![];
let mut ascii_enabled: bool = false;
for info in enabled_pf_info_base {
match info {
PfetchInfo::Palette => {
enabled_pf_info.push(PfetchInfo::BlankLine);
enabled_pf_info.push(PfetchInfo::Palette);
enabled_pf_info.push(PfetchInfo::BlankLine);
}
PfetchInfo::Ascii => {
ascii_enabled = true;
}
i => enabled_pf_info.push(i),
}
}
let readouts = Readouts {
general_readout: GeneralReadout::new(),
package_readout: PackageReadout::new(),
memory_readout: MemoryReadout::new(),
kernel_readout: KernelReadout::new(),
};
let os = get_info(&PfetchInfo::Os, &readouts).unwrap_or_default();
let logo_override = env::var("PF_ASCII");
let logo_name = logo_override.as_ref().unwrap_or(&os);
let mut logo = pfetch::logo(logo_name);
// color overrides
if let Ok(newcolor) = dotenv::var("PF_COL1") {
if let Ok(newcolor) = pfetch::Color::from_str(&newcolor) {
logo.primary_color = newcolor;
}
}
if let Ok(newcolor) = dotenv::var("PF_COL3") {
if let Ok(newcolor) = pfetch::Color::from_str(&newcolor) {
logo.secondary_color = newcolor;
}
}
let gathered_pfetch_info: Vec<(pfetch::Color, String, String)> = enabled_pf_info
.iter()
.filter_map(|info| {
let info_result = get_info(info, &readouts);
match info_result {
Some(info_str) => match info {
PfetchInfo::Title => Some((logo.secondary_color, info_str, "".to_string())),
PfetchInfo::Os => Some((logo.primary_color, info.to_string(), os.to_owned())),
PfetchInfo::BlankLine => {
Some((logo.primary_color, "".to_string(), "".to_string()))
}
PfetchInfo::Palette => Some((logo.primary_color, info_str, "".to_string())),
_ => Some((logo.primary_color, info.to_string(), info_str)),
},
None => None,
}
})
.collect();
pfetch(gathered_pfetch_info, logo, ascii_enabled);
}