├── .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 | --------------------------------------------------------------------------------