diff --git a/.gitignore b/.gitignore index 6ee01af..a3a0b6c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .vscode/ .DS_Store +.idea/ pridecat \ No newline at end of file diff --git a/Makefile b/Makefile index 815c27e..8d5938c 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CXX ?= clang all: pridecat pridecat: main.cpp - $(CXX) main.cpp -o pridecat -std=c++11 -lstdc++ -Wall -Wextra -O3 + $(CXX) main.cpp -o pridecat -std=c++17 -lstdc++ -Wall -Wextra -O3 install: pridecat cp pridecat /usr/local/bin/pridecat diff --git a/README.md b/README.md index 407b2c8..2ee306b 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,10 @@ Colorize your terminal output with pride! --pansexual,--pan Pansexual pride flag designed by Evie Varney in 2010 + +--progress-pride,--progress + Progress pride flag designed by Daniel Quasar in 2018 + --transgender,--trans Transgender pride flag designed by Monica Helms in 1999 @@ -73,10 +77,18 @@ Colorize your terminal output with pride! -T,--no-truecolor Force disable truecolor output (even if the terminal does seem to support it) +-s,--stretch + Stretch the flag to a certain height before repeating + -h,--help Display the help page ``` +## Installation (Linux) +```bash +curl -s https://raw.githubusercontent.com/lunasorcery/pridecat/main/install.sh | bash +``` + ## Building On any *nix system it _should_ be as simple as: @@ -87,7 +99,18 @@ cd pridecat make && make install ``` -This depends on a recent (C++11) C++ compiler being available. If you encounter issues, please let me know. +This depends on a recent (C++17) C++ compiler being available. If you encounter issues, please let me know. + +## Uninstall (Linux) +```bash +rm -f /usr/local/bin/pridecat +``` +or +``` +git clone https://github.com/lunasorcery/pridecat.git +cd pridecat +make uninstall +``` ## Windows support? diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..ee0d915 --- /dev/null +++ b/install.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +# Define the colors of the pride flag +RED='\033[38;2;228;3;3m' +ORANGE='\033[38;2;255;140;0m' +YELLOW='\033[38;2;255;237;0m' +GREEN='\033[38;2;0;128;38m' +BLUE='\033[38;2;0;77;255m' +PURPLE='\033[38;2;117;7;135m' +NC='\033[0m' # No Color + +# Print the Pridecat banner with pride flag colors +echo -e "${RED}mmmmm mmmmm mmmmm mmmm mmmmmm mmm mm mmmmmmm${NC}" +echo -e "${ORANGE}# \"# # \"# # # \"m # m\" \" ## # ${NC}" +echo -e "${YELLOW}#mmm#\" #mmmm\" # # # #mmmmm # # # # ${NC}" +echo -e "${GREEN}# # \"m # # # # # #mm# # ${NC}" +echo -e "${BLUE}# # \" mm#mm #mmm\" #mmmmm \"mmm\" # # # ${NC}" +echo -e "${PURPLE}Welcome to the Pridecat installation script!${NC}" + +printf "\n" + +echo -e "${GREEN}Do you want a simple or advanced setup? (s/a; default: s)${NC}" +read setup_type + +if [ "$setup_type" = "a" ]; then + echo -e "${RED}Advanced setup selected. ${NC}" + echo -e "${GREEN}Fetching forks...${NC}" + repos=$(curl -s https://api.github.com/repos/lunasorcery/pridecat/forks | jq -r '.[].full_name') + repos=("lunasorcery/pridecat" $repos) + + echo -e "${GREEN}Please select a repo (1 is the official repo):${NC}" + select repo in "${repos[@]}"; do + if [[ -n $repo ]]; then + echo -e "${GREEN}Using $repo${NC}" + break + else + echo -e "${RED}Invalid option${NC}" + exit 1 + fi + done + + echo -e "${GREEN}Fetching branches...${NC}" + branches=$(curl -s https://api.github.com/repos/$repo/branches | jq -r '.[].name') + if [ ${#branches[@]} -eq 1 ]; then + branch=${branches[0]} + echo -e "${GREEN}Only one branch found: $branch. Using it.${NC}" + else + echo -e "${GREEN}Please select a branch (1 is the main branch):${NC}" + select branch in "${branches[@]}"; do + if [[ -n $branch ]]; then + echo -e "${GREEN}Using $branch${NC}" + break + else + echo -e "${RED}Invalid option${NC}" + exit 1 + fi + done + fi + + echo -e "${GREEN}Setting up the advanced setup...${NC}" + mkdir .temp-pridecat + cd .temp-pridecat + echo -e "${GREEN}Downloading the files...${NC}" + wget https://raw.githubusercontent.com/$repo/$branch/Makefile > /dev/null 2>&1 + wget https://raw.githubusercontent.com/$repo/$branch/main.cpp > /dev/null 2>&1 + echo -e "${GREEN}Building and installing...${NC}" + make && sudo make install + echo -e "${GREEN}Cleaning up...${NC}" + cd .. + rm -rf .temp-pridecat + echo "Done!" | pridecat + +else + echo -e "${GREEN}Setting up the simple setup...${NC}" + mkdir .temp-pridecat + cd .temp-pridecat + echo -e "${GREEN}Downloading the files...${NC}" + wget https://raw.githubusercontent.com/lunasorcery/pridecat/main/Makefile > /dev/null 2>&1 + wget https://raw.githubusercontent.com/lunasorcery/pridecat/main/main.cpp > /dev/null 2>&1 + echo -e "${GREEN}Building and installing...${NC}" + make && sudo make install + echo -e "${GREEN}Cleaning up...${NC}" + cd .. + rm -rf .temp-pridecat + echo "Done!" | pridecat +fi \ No newline at end of file diff --git a/main.cpp b/main.cpp index 619b118..5844b5c 100644 --- a/main.cpp +++ b/main.cpp @@ -5,7 +5,9 @@ #include #include #include +#include #include +#include #if defined(_WIN32) #include #include @@ -15,7 +17,7 @@ struct color_t { uint8_t r,g,b; - color_t(uint32_t rgb) + color_t(const uint32_t rgb) : r((rgb >> 16) & 0xff) , g((rgb >> 8) & 0xff) , b(rgb & 0xff) @@ -24,9 +26,27 @@ struct color_t { : r(r), g(g), b(b) {} }; +enum class StretchRuleVertical : uint8_t { + Disallowed, // no stretching allowed + Allowed, // stretch vertically + PreserveTop, // repeat only the lase row so the details in the top of the flag are preserved + PreserveCenter, // last and first row are repeated to preserve the details in the center of the flag + PreserveBottom, // repeat only the first row so the details on the bottom side are preserved +}; + +enum class StretchRuleHorizontal : uint8_t { + Disallowed, // no stretching allowed + Allowed, // stretch horizontally + PreserveLeft, // repeat only the last column so the details on the left side are preserved + PreserveCenter, // last and first column are repeated to preserve the details in the center of the flag + PreserveRight, // repeat only the first column so the details on the right side are preserved +}; + struct flag_t { - std::vector colors; + std::variant, std::vector>> colors; std::string description; + StretchRuleVertical stretchVertical = StretchRuleVertical::Allowed; + StretchRuleHorizontal stretchHorizontal = StretchRuleHorizontal::Allowed; }; enum class colorAdjust : uint8_t { @@ -39,75 +59,75 @@ std::map allFlags = { { "lgbt", { // info: https://en.wikipedia.org/wiki/Rainbow_flag_(LGBT) // colors: https://en.wikipedia.org/wiki/File:Gay_Pride_Flag.svg - { 0xE40303, 0xFF8C00, 0xFFED00, 0x008026, 0x004Dff, 0x750787 }, + std::vector { 0xE40303, 0xFF8C00, 0xFFED00, 0x008026, 0x004Dff, 0x750787 }, "Classic 6-color rainbow flag popular since 1979" } }, { "lgbt-1978", { // info: https://en.wikipedia.org/wiki/Rainbow_flag_(LGBT) // colors: https://en.wikipedia.org/wiki/File:Gay_flag_8.svg - { 0xFF69B4, 0xFF0000, 0xFF8E00, 0xFFFF00, 0x008E00, 0x00C0C0, 0x400098, 0x8E008E }, + std::vector { 0xFF69B4, 0xFF0000, 0xFF8E00, 0xFFFF00, 0x008E00, 0x00C0C0, 0x400098, 0x8E008E }, "Original 8-color rainbow flag designed by Gilbert Baker in 1978" } }, { "lgbtpoc", { // info: https://en.wikipedia.org/wiki/Rainbow_flag_(LGBT) // colors: https://en.wikipedia.org/wiki/File:Philadelphia_Pride_Flag.svg - { 0x000000, 0x784F17, 0xE40303, 0xFF8C00, 0xFFED00, 0x008026, 0x004DFF, 0x750787 }, + std::vector { 0x000000, 0x784F17, 0xE40303, 0xFF8C00, 0xFFED00, 0x008026, 0x004DFF, 0x750787 }, "POC-inclusive rainbow flag designed by Philadelphia City Council in 2017" } }, { "transgender", { // info: https://en.wikipedia.org/wiki/Transgender_flags // colors: https://en.wikipedia.org/wiki/File:Transgender_Pride_flag.svg - { 0x5BCEFA, 0xF5A9B8, 0xFFFFFF, 0xF5A9B8, 0x5BCEFA }, + std::vector { 0x5BCEFA, 0xF5A9B8, 0xFFFFFF, 0xF5A9B8, 0x5BCEFA }, "Transgender pride flag designed by Monica Helms in 1999" } }, { "bisexual", { // info: https://en.wikipedia.org/wiki/Bisexual_pride_flag // colors: https://en.wikipedia.org/wiki/File:Bisexual_Pride_Flag.svg - { 0xD60270, 0xD60270, 0x9B4F96, 0x0038A8, 0x0038A8 }, + std::vector { 0xD60270, 0xD60270, 0x9B4F96, 0x0038A8, 0x0038A8 }, "Bisexual pride flag designed by Michael Page in 1998" } }, { "asexual", { // info: https://en.wikipedia.org/wiki/LGBT_symbols#Asexuality // colors: https://en.wikipedia.org/wiki/File:Asexual_Pride_Flag.svg - { 0x000000, 0xA3A3A3, 0xFFFFFF, 0x800080 }, + std::vector { 0x000000, 0xA3A3A3, 0xFFFFFF, 0x800080 }, "Asexual pride flag designed by AVEN user 'standup' in 2010" } }, { "aromantic", { // info/colors: https://cameronwhimsy.tumblr.com/post/75868343112/ive-been-reading-up-on-a-lot-of-the-discussion - { 0x3DA642, 0xA8D379, 0xFFFFFF, 0xA9A9A9, 0x000000 }, + std::vector { 0x3DA642, 0xA8D379, 0xFFFFFF, 0xA9A9A9, 0x000000 }, "Aromantic pride flag designed by Tumblr user 'cameronwhimsy' in 2014" } }, { "aromantic-asexual", { // info: https://www.lgbtqia.wiki/wiki/Aroace // colors: https://en.wikipedia.org/wiki/File:Aroace_flag.svg (also available from lgbtqia.wiki, but this is higher quality) - { 0xE28C00, 0xECCD00, 0xFFFFFF, 0x62AEDC, 0x203856 }, + std::vector { 0xE28C00, 0xECCD00, 0xFFFFFF, 0x62AEDC, 0x203856 }, "Aromantic-asexual pride flag designed by Tumblr user 'aroaesflags' in 2018" } }, { "pansexual", { // info: https://majesticmess.com/2018/12/01/interview-creator-of-the-pan-flag/ // colors: https://web.archive.org/web/20111103184455/http://pansexualflag.tumblr.com/post/1265215452/hex-color-codes-you-dont-have-to-use-these-exact - { 0xFF218C, 0xFF218C, 0xFFD800, 0xFFD800, 0x21B1FF, 0x21B1FF }, + std::vector { 0xFF218C, 0xFF218C, 0xFFD800, 0xFFD800, 0x21B1FF, 0x21B1FF }, "Pansexual pride flag designed by Evie Varney in 2010" } }, { "nonbinary", { // info: https://en.wikipedia.org/wiki/LGBT_symbols#Non-binary // colors: https://en.wikipedia.org/wiki/File:Nonbinary_flag.svg - { 0xFFF430, 0xFFFFFF, 0x9C59D1, 0x000000 }, + std::vector { 0xFFF430, 0xFFFFFF, 0x9C59D1, 0x000000 }, "Non-binary pride flag designed by Kye Rowan in 2014" } }, { "lipstick-lesbian", { // info/colors: https://en.wikipedia.org/wiki/File:Lipstick_Lesbian_flag_without_lips.svg - { 0xA40061, 0xB75592, 0xD063A6, 0xEDEDEB, 0xE4ACCF, 0xC54E54, 0x8A1E04 }, + std::vector { 0xA40061, 0xB75592, 0xD063A6, 0xEDEDEB, 0xE4ACCF, 0xC54E54, 0x8A1E04 }, "Lipstick lesbian pride flag designed by Natalie McCray in 2010" } }, @@ -115,22 +135,37 @@ std::map allFlags = { // info: https://en.wikipedia.org/wiki/LGBT_symbols#Lesbian // colors: https://en.wikipedia.org/wiki/File:Lesbian_pride_flag_2018.svg // second-last color changed from 0xB55690 to 0xB55590 to ensure distinct colors on non-truecolor displays - { 0xD52D00, 0xEF7627, 0xFF9A56, 0xFFFFFF, 0xD162A4, 0xB55590, 0xA30262 }, + std::vector { 0xD52D00, 0xEF7627, 0xFF9A56, 0xFFFFFF, 0xD162A4, 0xB55590, 0xA30262 }, "New lesbian pride flag designed by Emily Gwen in 2018" } }, { "community-lesbian", { // info/colors: https://majesticmess.com/encyclopedia/lesbian-flag-sadlesbeandisaster/ // more info: https://twitter.com/lesflagisracist/status/1107301651403157505 - { 0xD52D00, 0xFF9A56, 0xFFFFFF, 0xD362A4, 0xA30262 }, + std::vector { 0xD52D00, 0xFF9A56, 0xFFFFFF, 0xD362A4, 0xA30262 }, "5-color 'Community' variant designed by Tumblr user 'taqwomen' in 2018" } }, { "genderqueer", { // info/colors: https://genderqueerid.com/about-flag - { 0xB57EDC, 0xB57EDC, 0xFFFFFF, 0xFFFFFF, 0x4A8123, 0x4A8123 }, + std::vector { 0xB57EDC, 0xB57EDC, 0xFFFFFF, 0xFFFFFF, 0x4A8123, 0x4A8123 }, "Genderqueer pride flag designed by Marilyn Roxie in 2011" } }, + + { "progress-pride", { + // info/colors: https://de.wikipedia.org/wiki/Datei:LGBTQ+_rainbow_flag_Quasar_%22Progress%22_variant.svg + std::vector> { + { 0xf5a9b8, 0xf5a9b8, 0xf5a9b8, 0x5bcefa, 0x5bcefa, 0x5bcefa, 0x603917, 0x603917, 0x603917, 0x000000, 0x000000, 0x000000, 0xee3124, 0xee3124, 0xee3124, 0xee3124, 0xee3124, 0xee3124, 0xee3124 }, + { 0xffffff, 0xffffff, 0xffffff, 0xf5a9b8, 0xf5a9b8, 0xf5a9b8, 0x5bcefa, 0x5bcefa, 0x5bcefa, 0x603917, 0x603917, 0x603917, 0x000000, 0x000000, 0x000000, 0xf57e29, 0xf57e29, 0xf57e29, 0xf57e29 }, + { 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xf5a9b8, 0xf5a9b8, 0xf5a9b8, 0x5bcefa, 0x5bcefa, 0x5bcefa, 0x603917, 0x603917, 0x603917, 0x000000, 0x000000, 0x000000, 0xffee00 }, + { 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xf5a9b8, 0xf5a9b8, 0xf5a9b8, 0x5bcefa, 0x5bcefa, 0x5bcefa, 0x603917, 0x603917, 0x603917, 0x000000, 0x000000, 0x000000, 0x58b947 }, + { 0xffffff, 0xffffff, 0xffffff, 0xf5a9b8, 0xf5a9b8, 0xf5a9b8, 0x5bcefa, 0x5bcefa, 0x5bcefa, 0x603917, 0x603917, 0x603917, 0x000000, 0x000000, 0x000000, 0x0053a6, 0x0053a6, 0x0053a6, 0x0053a6 }, + { 0xf5a9b8, 0xf5a9b8, 0xf5a9b8, 0x5bcefa, 0x5bcefa, 0x5bcefa, 0x603917, 0x603917, 0x603917, 0x000000, 0x000000, 0x000000, 0x9f248f, 0x9f248f, 0x9f248f, 0x9f248f, 0x9f248f, 0x9f248f, 0x9f248f }, + }, + "Progress pride flag designed by Daniel Quasar in 2018", + StretchRuleVertical::Allowed, + StretchRuleHorizontal::PreserveLeft, // preserves the details on the left side + }} }; std::map aliases = { @@ -144,12 +179,189 @@ std::map aliases = { { "enby", "nonbinary" }, { "pink-lesbian", "lipstick-lesbian" }, { "lesbian", "community-lesbian" }, + { "progress", "progress-pride" }, }; +flag_t stretch1dFlagTo(const flag_t& flag, const int height) { + if (std::holds_alternative>>(flag.colors)) { + printf("WARNING: Method for stretching 1D flags called on 2D flag\n"); + return flag; + } + auto stretchedColors = std::get>(flag.colors); + switch (flag.stretchVertical) { + case StretchRuleVertical::Allowed: { + const int currentHeight = static_cast(stretchedColors.size()); + const std::vector unstretchedColors = stretchedColors; + if (currentHeight >= height) { + break; + } + stretchedColors.clear(); + const double stretchFactor = static_cast(height) / currentHeight; + for (int i = 0; i < height; ++i) { + int originalIndex = static_cast(i / stretchFactor); + if (originalIndex >= currentHeight) { + originalIndex = currentHeight-1; + } + stretchedColors.push_back(unstretchedColors[originalIndex]); + } + break; + } + case StretchRuleVertical::PreserveTop: { + while (static_cast(stretchedColors.size()) < height) { + stretchedColors.push_back(stretchedColors.back()); + } + break; + } + case StretchRuleVertical::PreserveCenter: { + const int delta_height = height - static_cast(stretchedColors.size()); + for (int i = 0; i < delta_height / 2; ++i) { + stretchedColors.insert(stretchedColors.begin(), stretchedColors.front()); + stretchedColors.push_back(stretchedColors.back()); + } + break; + } + case StretchRuleVertical::PreserveBottom: { + while (static_cast(stretchedColors.size()) < height) { + stretchedColors.insert(stretchedColors.begin(), stretchedColors.front()); + } + break; + } + default: + break; + } + return flag_t { + .colors = stretchedColors, + .description = flag.description, + .stretchVertical = flag.stretchVertical, + .stretchHorizontal = flag.stretchHorizontal + }; +} + +flag_t stretch2dFlagTo(const flag_t& flag, const int width, const int height) { + if (std::holds_alternative>(flag.colors)) { + printf("WARNING: Method for stretching 2D flags called on 1D flag\n"); + return flag; + } + auto stretchedColors = std::get>>(flag.colors); + switch (flag.stretchHorizontal) { + case StretchRuleHorizontal::Allowed: { + const int currentWidth = static_cast(stretchedColors[0].size()); + const std::vector> unstretchedColors = stretchedColors; + if (currentWidth >= width) { + break; + } + const double stretchFactor = static_cast(width) / currentWidth; + for (int row = 0; row < static_cast(unstretchedColors.size()); ++row) { + stretchedColors[row].clear(); + double error = 0.0; + for (int i = 0; i < width; ++i) { + const double exactOriginalIndex = i / stretchFactor; + int originalIndex = static_cast(exactOriginalIndex); + error += exactOriginalIndex - originalIndex; + if (error > 1.0) { + ++originalIndex; + error = 0.0; + } else if (error < -1.0) { + --originalIndex; + error = 0.0; + } + if (originalIndex < 0) { + originalIndex = 0; + } else if (originalIndex >= currentWidth) { + originalIndex = currentWidth-1; + } + stretchedColors[row].push_back(unstretchedColors[row][originalIndex]); + } + } + break; + } + case StretchRuleHorizontal::PreserveLeft: { + for (auto& row : stretchedColors) { + while (static_cast(row.size()) < width) { + row.push_back(row.back()); + } + } + break; + } + case StretchRuleHorizontal::PreserveCenter: { + const int delta_width = width - static_cast(stretchedColors[0].size()); + for (auto& row : stretchedColors) { + for (int i = 0; i < delta_width / 2; ++i) { + row.insert(row.begin(), row.front()); + row.push_back(row.back()); + } + } + break; + } + case StretchRuleHorizontal::PreserveRight: { + for (auto& row : stretchedColors) { + while (static_cast(row.size()) < width) { + row.insert(row.begin(), row.front()); + } + } + break; + } + default: + break; + } + switch (flag.stretchVertical) { + case StretchRuleVertical::Allowed: { + const int currentHeight = static_cast(stretchedColors.size()); + const std::vector> unstretchedColors = stretchedColors; + if (currentHeight >= height) { + break; + } + stretchedColors.clear(); + const double stretchFactor = static_cast(height) / currentHeight; + for (int i = 0; i < height; ++i) { + int originalIndex = static_cast(i / stretchFactor); + if (originalIndex >= currentHeight) { + originalIndex = currentHeight-1; + } + stretchedColors.insert(stretchedColors.begin() + i, unstretchedColors[originalIndex]); + } + break; + } + case StretchRuleVertical::PreserveTop: { + while (static_cast(stretchedColors.size()) < height) { + stretchedColors.push_back(stretchedColors.back()); + } + break; + } + case StretchRuleVertical::PreserveCenter: { + const int delta_height = height - static_cast(stretchedColors.size()); + for (int i = 0; i < delta_height / 2; ++i) { + stretchedColors.insert(stretchedColors.begin(), stretchedColors.front()); + stretchedColors.push_back(stretchedColors.back()); + } + break; + } + case StretchRuleVertical::PreserveBottom: { + while (static_cast(stretchedColors.size()) < height) { + stretchedColors.insert(stretchedColors.begin(), stretchedColors.front()); + } + break; + } + default: + break; + } + return flag_t { + .colors = stretchedColors, + .description = flag.description, + .stretchVertical = flag.stretchVertical, + .stretchHorizontal = flag.stretchHorizontal + }; +} + std::vector g_colorQueue; std::vector g_filesToCat; unsigned int g_currentRow = 0; -colorAdjust g_colorAdjustment = colorAdjust::none; +unsigned int g_currentColumn = 0; +bool two_dimensiona_flag = false; +flag_t current2dFlag; +auto g_colorAdjustment = colorAdjust::none; + +int stretchToHeight = 0; #if defined(_WIN32) bool g_useColors = _isatty(_fileno(stdout)); @@ -194,14 +406,29 @@ int bestNonTruecolorMatch(color_t const& color) { } void pushFlag(flag_t const& flag) { - for (color_t const& color : flag.colors) { - g_colorQueue.push_back(color); + if (std::holds_alternative>(flag.colors)) { + std::vector colors; + if (stretchToHeight != 0) { + const auto& stretchedFlag = stretch1dFlagTo(flag, stretchToHeight); + colors = std::get>(stretchedFlag.colors); + } else { + colors = std::get>(flag.colors); + } + for (color_t const& color : colors) { + g_colorQueue.push_back(color); + } + } else { + two_dimensiona_flag = true; + if (stretchToHeight != 0) { + current2dFlag = stretch2dFlagTo(flag, 0, stretchToHeight); + } else { + current2dFlag = flag; + } } } std::string resolveAlias(const std::string& arg) { - const auto& alias = aliases.find(arg); - if (alias != aliases.end()) { + if (const auto& alias = aliases.find(arg); alias != aliases.end()) { return alias->second; } return arg; @@ -209,13 +436,13 @@ std::string resolveAlias(const std::string& arg) { color_t adjustForReadability(color_t const& color) { if (g_colorAdjustment == colorAdjust::darken) { - return color_t( + return color_t( // NOLINT(*-return-braced-init-list) (color.r*3)/4, (color.g*3)/4, (color.b*3)/4 ); } else if (g_colorAdjustment == colorAdjust::lighten) { - return color_t( + return color_t( // NOLINT(*-return-braced-init-list) 64+(color.r*3)/4, 64+(color.g*3)/4, 64+(color.b*3)/4 @@ -281,34 +508,63 @@ void resetColor() { } } -void parseCommandLine(int argc, char** argv) { +void parseCommandLine(const int argc, char** argv) { bool finishedReadingFlags = false; for (int i = 1; i < argc; ++i) { if (finishedReadingFlags) { - g_filesToCat.push_back(argv[i]); + g_filesToCat.emplace_back(argv[i]); + } + else if (strEqual(argv[i], "-s") || strEqual(argv[i], "--stretch")) { + if (i + 1 < argc) { + try { + stretchToHeight = std::stoi(argv[++i]); + } catch (std::invalid_argument&) { + fprintf(stderr, "pridecat: Invalid height '%s'\n", argv[i]); + exit(1); + } + } else { + fprintf(stderr, "pridecat: Expected an argument after %s\n", argv[i]); + exit(1); + } } else if (strEqual(argv[i], "-h") || strEqual(argv[i], "--help")) { printf("pridecat!\n"); printf("It's like cat but more colorful :)\n"); printf("\nCurrently available flags:\n"); - for (const auto& flag : allFlags) { - printf(" --%s", flag.first.c_str()); - for (const auto& alias : aliases) { - if (flag.first == alias.second) { - printf(",--%s", alias.first.c_str()); + for (const auto&[name, flag] : allFlags) { + printf(" --%s", name.c_str()); + for (const auto&[short_name, long_name] : aliases) { + if (name == long_name) { + printf(",--%s", short_name.c_str()); } } if (g_useColors) { putc(' ', stdout); - for (const auto& color : flag.second.colors) { - setBackgroundColor(color); - putc(' ', stdout); + if (std::holds_alternative>(flag.colors)) { + for (const color_t color : std::get>(flag.colors)) { + setBackgroundColor(color); + putc(' ', stdout); + } + } else { + auto& colors = std::get>>(flag.colors); + flag_t newFlag = flag; + if (colors[0].size() < 30) { + newFlag.colors = stretch2dFlagTo(flag, 30, 6).colors; + } + for (const std::vector& color_row : std::get>>(newFlag.colors)) { + printf("\n "); + for (const color_t color : color_row) { + setBackgroundColor(color); + putc(' ', stdout); + } + resetBackgroundColor(); + } } resetBackgroundColor(); } printf("\n"); - printf(" %s\n\n", flag.second.description.c_str()); + printf(" %s\n\n", flag.description.c_str()); } printf("Additional options:\n"); @@ -324,6 +580,8 @@ void parseCommandLine(int argc, char** argv) { printf(" Lighten colors slightly for improved readability on dark backgrounds\n\n"); printf(" -d,--darken\n"); printf(" Darken colors slightly for improved readability on light backgrounds\n\n"); + printf(" -s,--stretch \n"); + printf(" Stretch the flag to a certain height before repeating\n\n"); printf(" -h,--help\n"); printf(" Display this message\n\n"); @@ -367,10 +625,10 @@ void parseCommandLine(int argc, char** argv) { else if (strEqual(argv[i], "-")) { // use an empty string in the array to represent stdin // so we can still actually have a file called '-' - g_filesToCat.push_back(""); + g_filesToCat.emplace_back(""); } else { - g_filesToCat.push_back(argv[i]); + g_filesToCat.emplace_back(argv[i]); } } } @@ -380,7 +638,51 @@ void abortHandler(int signo) { exit(signo); } +void catFile2d(FILE* fh) { + int longestLine = 0; + char* line = nullptr; + size_t len = 0; + ssize_t read; + + while ((read = getline(&line, &len, fh)) != -1) { + if (read > longestLine) { + longestLine = static_cast(read); + } + } + fseek(fh, 0, SEEK_SET); + + const int flagHeight = static_cast(std::get>>(current2dFlag.colors).size()); + const auto flag = stretch2dFlagTo(current2dFlag, longestLine, flagHeight); + const auto& colors = std::get>>(flag.colors); + + + int c; + while ((c = getc(fh)) >= 0) { + if (c == '\n') { + g_currentRow++; + g_currentColumn = 0; + if (g_currentRow == colors.size()) { + g_currentRow = 0; + } + resetColor(); + putc(c, stdout); + } else { + setColor(colors[g_currentRow][g_currentColumn]); + putc(c, stdout); + resetColor(); + g_currentColumn++; + } + } + + if (line) { + free(line); + } +} + void catFile(FILE* fh) { + if (two_dimensiona_flag) { + catFile2d(fh); + } int c; while ((c = getc(fh)) >= 0) { if (c == '\n') { @@ -440,7 +742,7 @@ int main(int argc, char** argv) { catFile(stdin); } else { for (auto const& filepath : g_filesToCat) { - if (filepath == "") { + if (filepath.empty()) { catFile(stdin); } else { FILE* fh = fopen(filepath.c_str(), "rb");