├── .gitignore
├── LICENSE
├── README.md
├── build-static
├── src
├── helpers
│ ├── functions.cpp
│ └── functions.hpp
├── info
│ ├── cpu.cpp
│ ├── distro.cpp
│ ├── environment.cpp
│ ├── memory.cpp
│ ├── music.cpp
│ ├── packages.cpp
│ ├── packages.hpp
│ ├── term.cpp
│ └── uptime.cpp
├── main.cpp
└── main.hpp
└── xmake.lua
/.gitignore:
--------------------------------------------------------------------------------
1 | # Blacklist everything by default.
2 | *
3 |
4 | # Whitelist the gitignore, license, readme, meson config,
5 | # and all files in the source dir.
6 | !.gitignore
7 | !build-static
8 | !LICENSE
9 | !README.md
10 | !src/
11 | !src/*
12 | !src/*/*
13 | !xmake.lua
14 |
15 | # Any Emacs-related files, placed at the end to
16 | # overwite the whitelist rules above.
17 | *~
18 | \#*\#
19 | .\#*
20 |
21 | # Vim swap files
22 | [._]*.s[a-v][a-z]
23 | *.svg # comment out if you don't need vector files
24 | [._]*.sw[a-p]
25 | [._]s[a-rt-v][a-z]
26 | [._]ss[a-gi-z]
27 | [._]sw[a-p]
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | EVERYTHING UNDER THIS LICENSE IS PLACED INTO THE PUBLIC DOMAIN
2 | ALL COPYRIGHTS (AND BY EXTENSION THEIR RESTRICTIONS) ARE HEREBY REVOKED
3 |
4 | IN JURISDICTIONS THAT DO NOT ALLOW YOU TO REVOKE COPYRIGHT, USE THESE AS THE CONDITIONS:
5 | - THERE ARE NO RESTRICTIONS
6 | - YOU CAN LITERALLY DO WHATEVER YOU WANT
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cppfetch
2 |
3 | I decided to learn CPP, and I'm using this project as way to actively learn it.
4 |
5 | I decided an information gathering program because I'm already accustomed to making
6 | such programs in other languages.
7 |
8 | ## Building
9 |
10 | Dependencies:
11 | - xmake
12 | - libmpdclient\*
13 |
14 | \*(Should automatically be installed/compiled with xmake when the music option is enabled.
15 | However if you find it doesn't install, open an issue with the message with the
16 | output of xmake and then try installing libmpdclient from a package manager
17 | (though I'm usually really responsive so I'll probably have it fixed up for you before you have to).)
18 |
19 | ```bash
20 | git clone https://github.com/Phate6660/cppfetch
21 | cd cppfetch
22 | xmake # or `xmake f --music=y -v && xmake -v` if you want to enable music info
23 | ```
24 |
25 | (Use `xmake -rv` after the `&&` to have xmake rebuild everything.
26 | It's only needed if you previously built cppfetch with/without music and want the opposite.)
27 |
28 | You may also statically build the program with `./build-static`.
29 | It only requires g++ and strip (which you should already have if you're building programs :D).
30 | However, building with music support only works if you built libmpdclient as a static lib.
31 | If you have done that and want music support, then run `./build-static true`.
32 |
33 | ## Example output
34 |
35 | `xmake run` or `xmake run cppfetch l` (if you want the logo to be displayed too)
36 |
37 | ```
38 | ██████╗██████╗ ██████╗ ███████╗███████╗████████╗ ██████╗██╗ ██╗
39 | ██╔════╝██╔══██╗██╔══██╗██╔════╝██╔════╝╚══██╔══╝██╔════╝██║ ██║
40 | ██║ ██████╔╝██████╔╝█████╗ █████╗ ██║ ██║ ███████║
41 | ██║ ██╔═══╝ ██╔═══╝ ██╔══╝ ██╔══╝ ██║ ██║ ██╔══██║
42 | ╚██████╗██║ ██║ ██║ ███████╗ ██║ ╚██████╗██║ ██║
43 | ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═════╝╚═╝ ╚═╝
44 | CPU: Intel(R) Core(TM) i5-3470 CPU @ 3.20GHz
45 | Distro: Gentoo/Linux
46 | Editor: /usr/bin/nvim
47 | Environment: herbstluftwm
48 | Memory: 15966MB
49 | Music: Electric Six - I Shall Exterminate Everything Around Me That Restricts Me From Being The Master - It's Showtime!
50 | Packages: 594 (Portage)
51 | Shell: /bin/bash
52 | Terminal: xterm
53 | Uptime: 6d 3h 44m
54 | User: valley
55 | ```
56 |
57 | You'll find the binary at: `./build/linux/ARCH/cppfetch`
58 |
59 | (Replace ARCH with your architecture, e.g. x86\_64.)
60 | ## TODO
61 |
62 | - ~~ASCII art~~
63 | + ~~Disabled by default, enable with `l` or `logo`~~
64 | + ~~Hardoded ascii art~~
65 | + ~~User supplied ascii art~~ (place at `~/.config/cppfetch/logo`)
66 | - ~~CPU Info~~
67 | - ~~DE/WM Info~~
68 | - ~~Distro Info~~
69 | - ~~Editor Info~~
70 | - Memory Info
71 | + Proper formatting (e.g. decimal points / extra calculations where necessary)
72 | + ~~Total~~
73 | + Used
74 | - Music Info
75 | + ~~MPD~~
76 | - Package Count
77 | + ~~apt~~
78 | + cargo
79 | + ~~dnf~~
80 | + ~~dpkg~~
81 | + ~~eopkg~~
82 | + flatpak
83 | + ~~pacman~~
84 | + pip
85 | + ~~[pkg](https://github.com/Phate6660/pkg)~~
86 | + [ppkg](https://github.com/Phate6660/ppkg)
87 | + ~~qlist~~ (TODO: get package counts in pure C++)
88 | + ~~rpm~~
89 | + ~~xbps~~
90 | + yum
91 | - ~~Shell Info~~
92 | - ~~Terminal Info~~
93 | - ~~Uptime Info~~
94 | - ~~User Info~~
95 |
--------------------------------------------------------------------------------
/build-static:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | COMMON_ARGS="-march=native -std=c++2a -static -o cppfetch src/main.cpp src/helpers/functions.cpp"
4 |
5 | if [ "$1" == true ]; then
6 | ARGS=("-DMUSIC" src/info/*.cpp "-lmpdclient")
7 | else
8 | ARGS=(src/info/{cpu,distro,environment,memory,packages,term,uptime}.cpp)
9 | fi
10 |
11 | # Compile the binary.
12 | COMMAND="g++ ${COMMON_ARGS} ${ARGS[*]}"
13 | eval "${COMMAND}"
14 | # Strip the binary (usually for things like debug symbols).
15 | strip cppfetch
16 | # For verifying if the binary is static and stripped.
17 | file cppfetch
18 |
--------------------------------------------------------------------------------
/src/helpers/functions.cpp:
--------------------------------------------------------------------------------
1 | // This file contains re-usable functions for the project
2 | #include
3 | #include
4 | #include
5 | #include "functions.hpp"
6 |
7 | // Thank you StackOverflow.
8 | bool isWanted(const std::string & line, std::string field) {
9 | return (line.find(field) != std::string::npos);
10 | }
11 |
12 | // Thanks to StackOverflow, using this to split a string based on a delimiter.
13 | std::vector explode(const std::string& str, const char& ch) {
14 | std::string next;
15 | std::vector result;
16 |
17 | // For each character in the string.
18 | for (std::string::const_iterator it = str.begin(); it != str.end(); it++) {
19 | // If we've hit the terminal character.
20 | if (*it == ch) {
21 | // If we have some characters accumulated.
22 | if (!next.empty()) {
23 | // Add them to the result vector.
24 | result.push_back(next);
25 | next.clear();
26 | }
27 | } else {
28 | next += *it; // Accumulate the next character into the sequence.
29 | }
30 | }
31 | if (!next.empty())
32 | result.push_back(next);
33 | return result;
34 | }
35 |
36 | std::string parse(std::string field, std::string file) {
37 | std::ifstream thefile(file); // Open the file for reading.
38 | std::string output,line,line_pre_array;
39 | while (getline(thefile, line)) {
40 | if (isWanted(line, field))
41 | line_pre_array = line;
42 | }
43 | thefile.close(); // Close the file.
44 | return line_pre_array;
45 | }
46 |
--------------------------------------------------------------------------------
/src/helpers/functions.hpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #pragma once
4 |
5 | bool isWanted(const std::string & line, std::string field);
6 | std::vector explode(const std::string& str, const char& ch);
7 | std::string parse(std::string field, std::string file);
8 |
--------------------------------------------------------------------------------
/src/info/cpu.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "../helpers/functions.hpp"
3 |
4 | std::string cpu() {
5 | std::string cpu;
6 | std::string line_pre_array = parse("model name", "/proc/cpuinfo");
7 | std::vector result = explode(line_pre_array, ':');
8 | cpu = result[1];
9 | cpu = std::regex_replace(cpu, std::regex("^ +"), "");
10 | return cpu;
11 | }
12 |
--------------------------------------------------------------------------------
/src/info/distro.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "../helpers/functions.hpp"
5 |
6 | std::string extract(std::string file) {
7 | std::string distro;
8 | std::string line_pre_array = parse("PRETTY_NAME", file);
9 | std::vector result = explode(line_pre_array, '=');
10 | distro = result[1]; // Second element.
11 | // Trim `"` from the string.
12 | distro.erase(std::remove(distro.begin(), distro.end(), '\"'), distro.end());
13 | return distro;
14 | }
15 |
16 | // Parse `/etc/os-release` for the PRETTY_NAME string
17 | // and extract the value of the variable.
18 | // Returns the name of the distro.
19 | // Example: Gentoo/Linux.
20 | std::string distro() {
21 | // Check if running Android.
22 | if (std::system("which getprop > /dev/null 2>&1")) {
23 | // No getprop command, resume as normal.
24 | std::filesystem::path bedrock_file = "/bedrock/etc/os-release";
25 | std::filesystem::path normal_file = "/etc/os-release";
26 | std::filesystem::path weird_file = "/var/lib/os-release";
27 | if (std::filesystem::exists(bedrock_file)) {
28 | return extract("/bedrock/etc/os-release");
29 | } else if (std::filesystem::exists(normal_file)) {
30 | return extract("/etc/os-release");
31 | } else if (std::filesystem::exists(weird_file)) {
32 | return extract("/var/lib/os-release");
33 | } else {
34 | return "N/A (could not read '/bedrock/etc/os-release', '/etc/os-release', nor '/var/lib/os-release')";
35 | }
36 | } else {
37 | // getprop command found, return Android version.
38 | const std::string& command = "getprop ro.build.version.release";
39 | std::system((command + " > temp.txt").c_str());
40 |
41 | std::ifstream ifs("temp.txt");
42 | std::string ret{ std::istreambuf_iterator(ifs), std::istreambuf_iterator() };
43 | ifs.close(); // must close the inout stream so the file can be cleaned up
44 | if (std::remove("temp.txt") != 0) {
45 | perror("Error deleting temporary file");
46 | }
47 | std::string message = "Android " + ret;
48 | message.erase(std::remove(message.begin(), message.end(), '\n'), message.end());
49 | return message;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/info/environment.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "../helpers/functions.hpp"
5 |
6 | std::string de_wm() {
7 | char * val;
8 |
9 | // Desktop Environment checking.
10 | val = std::getenv("XDG_DESKTOP_SESSION");
11 | if (val != NULL) {
12 | std::string de = val;
13 | return de;
14 | }
15 | val = std::getenv("XDG_CURRENT_DESKTOP");
16 | if (val != NULL) {
17 | std::string de = val;
18 | return de;
19 | }
20 | val = std::getenv("DESKTOP_SESSION");
21 | if (val != NULL) {
22 | std::string de = val;
23 | return de;
24 | }
25 |
26 | // Window Manager checking.
27 | val = std::getenv("HOME");
28 | std::string home = val;
29 | std::string xinitrc{
30 | std::system("which getprop > /dev/null 2>&1") ?
31 | home.append("/.xinitrc")
32 | : home.append("/.vnc/xstartup") };
33 | std::ifstream file;
34 | // Thank you StackOverflow for lines 34-53.
35 | // It reads the last line of the file by by going to one character before EOF
36 | // and then reading backwards until it hits a newline character.
37 | file.open(xinitrc.c_str(), std::fstream::in);
38 | if(file.is_open()) {
39 | // Got to the last character before EOF.
40 | file.seekg(-1, std::ios_base::end);
41 | if(file.peek() == '\n') {
42 | // Start searching for \n occurrences.
43 | file.seekg(-1, std::ios_base::cur);
44 | int i = file.tellg();
45 | for(;i > 0; i--) {
46 | if(file.peek() == '\n') {
47 | //Found
48 | file.get();
49 | break;
50 | }
51 | // Move one character back.
52 | file.seekg(i, std::ios_base::beg);
53 | }
54 | }
55 | std::string lastline;
56 | getline(file, lastline);
57 | std::vector wm_vector = explode(lastline, ' ');
58 | int n = wm_vector.size();
59 | int element{
60 | std::system("which getprop > /dev/null 2>&1") ?
61 | n - 1
62 | : 0 };
63 | std::string wm = wm_vector[element];
64 | return wm;
65 | } else {
66 | return "N/A (could not open " + xinitrc + ")";
67 | }
68 | }
69 |
70 | std::string editor() {
71 | char * val{ std::getenv("EDITOR") };
72 | if (val != NULL) {
73 | std::string editor = val;
74 | return editor;
75 | } else {
76 | return "N/A (could not read $EDITOR, is it set?)";
77 | }
78 | }
79 |
80 | std::string shell() {
81 | char * val{ std::getenv("SHELL") };
82 | if (val != NULL) {
83 | std::string shell = val;
84 | return shell;
85 | } else {
86 | return "N/A (could not read $SHELL)";
87 | }
88 | }
89 |
90 | std::string user() {
91 | char * val{ std::getenv("USER") };
92 | if (val != NULL) {
93 | std::string user = val;
94 | return user;
95 | } else {
96 | return "N/A (could not read $USER)";
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/info/memory.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "../helpers/functions.hpp"
4 |
5 | std::string memory() {
6 | std::string total_line = parse("MemTotal", "/proc/meminfo");
7 | std::vector total_line_vector = explode(total_line, ' ');
8 | int total_size = std::stoi(total_line_vector[1]);
9 | if (total_size > 1024) {
10 | int total = total_size / 1024;
11 | std::string message_total = std::to_string(total);
12 | std::string message = message_total + "MB";
13 | return message;
14 | } else {
15 | std::string message_total = std::to_string(total_size);
16 | std::string message = message_total + "KB";
17 | return message;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/info/music.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | std::string music() {
5 | struct mpd_connection *conn;
6 |
7 | conn = mpd_connection_new("localhost", 6600, 1000);
8 |
9 | if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) {
10 | mpd_connection_free(conn);
11 | return "N/A (could not connect to MPD)";
12 | }
13 | struct mpd_song *song;
14 | song = mpd_run_current_song(conn);
15 | const char *title_char = mpd_song_get_tag(song, MPD_TAG_TITLE, 0);
16 | const char *album_char = mpd_song_get_tag(song, MPD_TAG_ALBUM, 0);
17 | const char *artist_char = mpd_song_get_tag(song, MPD_TAG_ARTIST, 0);
18 | std::string title = title_char;
19 | std::string album = album_char;
20 | std::string artist = artist_char;
21 | std::string message = artist
22 | + std::string(" - ")
23 | + album
24 | + std::string(" - ")
25 | + title;
26 | return message;
27 | }
28 |
--------------------------------------------------------------------------------
/src/info/packages.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "packages.hpp"
4 |
5 | /// Run the command and count the lines of output,
6 | /// optionally subtract from the count to account for extra lines,
7 | /// then assemble and return the message as a string.
8 | static std::string count(std::string cmd, std::string manager, int remove = 0) {
9 | const std::string& command = cmd + "| wc -l";
10 | std::system((command + " > temp.txt").c_str());
11 |
12 | std::ifstream ifs("temp.txt");
13 | std::string ret{ std::istreambuf_iterator(ifs), std::istreambuf_iterator() };
14 | ifs.close(); // must close the inout stream so the file can be cleaned up
15 | if (std::remove("temp.txt") != 0) {
16 | perror("Error deleting temporary file");
17 | }
18 | int amount = std::stoi(ret);
19 | amount = amount - remove;
20 | std::string message = ret + " (" + manager + ")";
21 | message.erase(std::remove(message.begin(), message.end(), '\n'), message.end());
22 | return message;
23 | }
24 |
25 | static PackageManager findPackageManager() {
26 | if (std::system("which apk > /dev/null 2>&1") == 0) {
27 | return APK;
28 | } else if (std::system("which dnf > /dev/null 2>&1") == 0) {
29 | return DNF;
30 | } else if (std::system("which dpkg-query > /dev/null 2>&1") == 0) {
31 | return DPKG;
32 | } else if (std::system("which eopkg > /dev/null 2>&1") == 0) {
33 | return EOPKG;
34 | } else if (std::system("which pacman > /dev/null 2>&1") == 0) {
35 | return PACMAN;
36 | } else if (std::system("which pkg > /dev/null 2>&1") == 0) {
37 | return PKG;
38 | } else if (std::system("which qlist > /dev/null 2>&1") == 0) {
39 | return QLIST;
40 | } else if (std::system("which rpm > /dev/null 2>&1") == 0) {
41 | return RPM;
42 | } else if (std::system("which xbps-query > /dev/null 2>&1") == 0) {
43 | return XBPS;
44 | } else {
45 | return UNKNOWN;
46 | }
47 | }
48 |
49 | // Return package counts.
50 | std::string packages() {
51 | switch (findPackageManager()) {
52 | case APK:
53 | return count("apk info", "apk");
54 | case DNF:
55 | return count("dnf list installed", "dnf");
56 | case DPKG:
57 | return count("dpkg-query -f '${binary:Package}\n' -W", "dpkg");
58 | case EOPKG:
59 | return count("eopkg list-installed", "eopkg");
60 | case PACMAN:
61 | return count("pacman -Qq", "pacman");
62 | case PKG:
63 | return count("pkg -l", "Portage");
64 | case QLIST:
65 | return count("qlist -I", "Portage");
66 | case RPM:
67 | return count("rpm -qa", "rpm");
68 | case XBPS:
69 | return count("xbps-query -l", "xbps");
70 | default: return "N/A (no supported pacakge managers found)";
71 | }
72 | }
73 |
74 |
--------------------------------------------------------------------------------
/src/info/packages.hpp:
--------------------------------------------------------------------------------
1 | enum PackageManager {
2 | UNKNOWN,
3 | APK, // apk -- package manager for Alpine Linux.
4 | DNF, // dnf -- package manager for Red Hat distros.
5 | DPKG, // dpkg -- same as apt.
6 | EOPKG, // eopkg -- Solus package manager.
7 | PACMAN, // pacman -- Arch package manager.
8 | PIP, // pip -- Python's package manager.
9 | PKG, // pkg -- emerge frontend written in Rust.
10 | QLIST, // qlist -- list package info for Portage.
11 | RPM, // rpm -- like dnf.
12 | XBPS, // xbps -- Void Linux's package manager.
13 | };
14 |
--------------------------------------------------------------------------------
/src/info/term.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "../helpers/functions.hpp"
5 |
6 | /*
7 | * Credits to https://www.techiedelight.com/trim-string-cpp-remove-leading-trailing-spaces/
8 | * for WHITESPACE, ltrim, rtrim, and trim.
9 | */
10 |
11 | const std::string WHITESPACE = " \n\r\t\f\v";
12 |
13 | std::string ltrim(const std::string& s) {
14 | size_t start = s.find_first_not_of(WHITESPACE);
15 | return (start == std::string::npos) ? "" : s.substr(start);
16 | }
17 |
18 | std::string rtrim(const std::string& s) {
19 | size_t end = s.find_last_not_of(WHITESPACE);
20 | return (end == std::string::npos) ? "" : s.substr(0, end + 1);
21 | }
22 |
23 | std::string trim(const std::string& s) {
24 | return rtrim(ltrim(s));
25 | }
26 |
27 | std::string get_pid(std::string pid) {
28 | std::string path = "/proc/" + pid + "/status";
29 | std::string line = parse("PPid", path);
30 | return trim(explode(line, ':')[1]);
31 | }
32 |
33 | std::string get_pname(std::string pid) {
34 | std::string pppid = get_pid(pid);
35 | std::string new_path = "/proc/" + pppid + "/status";
36 | std::string new_line = parse("Name", new_path);
37 | return trim(explode(new_line, ':')[1]);
38 | }
39 |
40 | std::string find_terminal(std::string ppid) {
41 | std::string pppid = get_pid(ppid);
42 | std::string pppname = get_pname(ppid);
43 | /* If the process name is "bash" or "general" (a script I made for general functions),
44 | * keep going to look for an actual terminal. I often use a nested bash session inside
45 | * of a bash session, so check for it one more time as well. That should be all that's needed.
46 | * TODO: Add more exceptionms, IIRC from other fetch programs I worked on, I need
47 | * to add workarounds for running in scripts, tmux, and
48 | * I believe there was a systemd issue too. */
49 | if (pppname == "bash" || pppname == "general") {
50 | std::string new_pppname = get_pname(pppid);
51 | if (new_pppname == "bash") {
52 | std::string new_pppid = get_pid(pppid);
53 | return get_pname(new_pppid);
54 | } else {
55 | return new_pppname;
56 | }
57 | } else {
58 | return pppname;
59 | }
60 | }
61 |
62 | std::string terminal() {
63 | std::string ppid{ std::to_string(getppid()) };
64 | return find_terminal(ppid);
65 | }
66 |
--------------------------------------------------------------------------------
/src/info/uptime.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "../helpers/functions.hpp"
4 |
5 | std::string uptime() {
6 | std::ifstream uptime_file("/proc/uptime"); // Open the file for reading.
7 | std::string line,uptime_pre_calculation;
8 | int uptime;
9 | uptime_pre_calculation.assign(
10 | (std::istreambuf_iterator(uptime_file)),
11 | (std::istreambuf_iterator())
12 | );
13 | uptime_file.close(); // Close the file.
14 | // Create the vector from the string with the delimiter.
15 | std::vector result = explode(uptime_pre_calculation, ' ');
16 | result = explode(result[0], '.');
17 | uptime = std::stoi(result[0]);
18 | if (uptime > 86400) {
19 | int days = uptime / 60 / 60 / 24;
20 | int hours = (uptime / 60 / 60) % 24;
21 | int minutes = (uptime / 60) % 60;
22 | std::string output = std::to_string(days) + "d "
23 | + std::to_string(hours) + "h "
24 | + std::to_string(minutes) + "m";
25 | return output;
26 | } else if (uptime > 3600) {
27 | int hours = (uptime / 60 / 60) % 24;
28 | int minutes = (uptime / 60) % 60;
29 | std::string output = std::to_string(hours) + "h "
30 | + std::to_string(minutes) + "m";
31 | return output;
32 | } else if (uptime > 60) {
33 | int minutes = (uptime / 60) % 60;
34 | return std::to_string(minutes) + "m";
35 | } else {
36 | return "<1m";
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "main.hpp"
5 |
6 | void logo() {
7 | char * val = std::getenv("HOME");
8 | std::string home = val;
9 | std::string logo_file = home.append("/.config/cppfetch/logo");
10 | std::filesystem::path f{ logo_file };
11 | // Automatically use custom ascii art if the file exists,
12 | // otherwise use the default hardcoded logo.
13 | if (std::filesystem::exists(f)) {
14 | std::ifstream ifs(logo_file);
15 | std::string ret{ std::istreambuf_iterator(ifs), std::istreambuf_iterator() };
16 | ifs.close(); // must close the inout stream so the file can be cleaned up
17 | std::cout << ret;
18 | } else {
19 | std::cout <<
20 | " ██████╗██████╗ ██████╗ ███████╗███████╗████████╗ ██████╗██╗ ██╗" << std::endl <<
21 | "██╔════╝██╔══██╗██╔══██╗██╔════╝██╔════╝╚══██╔══╝██╔════╝██║ ██║" << std::endl <<
22 | "██║ ██████╔╝██████╔╝█████╗ █████╗ ██║ ██║ ███████║" << std::endl <<
23 | "██║ ██╔═══╝ ██╔═══╝ ██╔══╝ ██╔══╝ ██║ ██║ ██╔══██║" << std::endl <<
24 | "╚██████╗██║ ██║ ██║ ███████╗ ██║ ╚██████╗██║ ██║" << std::endl <<
25 | " ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═════╝╚═╝ ╚═╝" << std::endl;
26 | }
27 | }
28 |
29 | void output() {
30 | std::cout <<
31 | "CPU: " << cpu() << std::endl <<
32 | "Distro: " << distro() << std::endl <<
33 | "Editor: " << editor() << std::endl <<
34 | "Environment: " << de_wm() << std::endl <<
35 | "Memory: " << memory() << std::endl <<
36 | #ifdef MUSIC
37 | "Music: " << music() << std::endl <<
38 | #endif
39 | "Packages: " << packages() << std::endl <<
40 | "Shell: " << shell() << std::endl <<
41 | "Terminal: " << terminal() << std::endl <<
42 | "Uptime: " << uptime() << std::endl <<
43 | "User: " << user() << std::endl;
44 | }
45 |
46 | int main(int argc, char** argv) {
47 | if (argc > 1) {
48 | std::string arg = argv[1];
49 |
50 | // Print help if `h` or `help` is passed.
51 | if (arg == "h" || arg == "help") {
52 | std::cout <<
53 | "`l` or `logo` -- enable logo" <<
54 | std::endl;
55 | return 0;
56 | }
57 | if (arg == "l" || arg == "logo") {
58 | logo();
59 | output();
60 | }
61 | } else {
62 | output();
63 | return 0;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main.hpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #pragma once
4 |
5 | std::string cpu();
6 | std::string de_wm();
7 | std::string distro();
8 | std::string editor();
9 | std::string memory();
10 | #ifdef MUSIC
11 | std::string music();
12 | #endif
13 | std::string packages();
14 | std::string shell();
15 | std::string terminal();
16 | std::string uptime();
17 | std::string user();
18 |
--------------------------------------------------------------------------------
/xmake.lua:
--------------------------------------------------------------------------------
1 | set_project("cppfetch")
2 | set_config("cxxflags", "-std=c++2a")
3 |
4 | option("music")
5 | set_default(false)
6 | set_description("Enable music info, require libmpdclient.")
7 | set_showmenu(true)
8 | add_defines("MUSIC")
9 | option_end()
10 |
11 | if has_config("music") then
12 | add_requires("libmpdclient")
13 | end
14 |
15 | target("cppfetch")
16 | set_kind("binary")
17 | set_options("music")
18 | on_load(function (target)
19 | local _, compiler_name = target:tool("cc")
20 | if compiler_name == "clang" then
21 | print("WARNING: BUILDING WITH CLANG IS UNSUPPORTED (IN FACT IT'S BROKEN), PLEASE CONTINUE AT YOUR OWN RISK.")
22 | end
23 | end)
24 | add_files("src/main.cpp")
25 | add_files("src/helpers/functions.cpp")
26 | add_files("src/info/cpu.cpp")
27 | add_files("src/info/distro.cpp")
28 | add_files("src/info/environment.cpp")
29 | add_files("src/info/memory.cpp")
30 | if has_config("music") then
31 | add_packages("libmpdclient")
32 | add_files("src/info/music.cpp")
33 | end
34 | add_files("src/info/packages.cpp")
35 | add_files("src/info/term.cpp")
36 | add_files("src/info/uptime.cpp")
37 |
--------------------------------------------------------------------------------