diff --git a/CMakeLists.txt b/CMakeLists.txt index 7663965af..b3b487584 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -260,6 +260,7 @@ set(LIBFASTFETCH_SRC src/logo/image/im7.c src/logo/image/image.c src/logo/logo.c + src/logo/option.c src/modules/battery/battery.c src/modules/bios/bios.c src/modules/bluetooth.c diff --git a/src/common/init.c b/src/common/init.c index aa427b2d0..8d2e7a48f 100644 --- a/src/common/init.c +++ b/src/common/init.c @@ -3,6 +3,7 @@ #include "common/thread.h" #include "detection/displayserver/displayserver.h" #include "util/textModifier.h" +#include "logo/logo.h" #include #include @@ -36,23 +37,7 @@ static void initModuleArg(FFModuleArgs* args) static void defaultConfig(FFinstance* instance) { - ffStrbufInitA(&instance->config.logo.source, 0); - instance->config.logo.type = FF_LOGO_TYPE_AUTO; - for(uint8_t i = 0; i < (uint8_t) FASTFETCH_LOGO_MAX_COLORS; ++i) - ffStrbufInit(&instance->config.logo.colors[i]); - instance->config.logo.width = 0; - instance->config.logo.height = 0; //preserve aspect ratio - instance->config.logo.paddingTop = 0; - instance->config.logo.paddingLeft = 0; - instance->config.logo.paddingRight = 4; - instance->config.logo.printRemaining = true; - instance->config.logo.preserveAspectRadio = false; - - instance->config.logo.chafaFgOnly = false; - ffStrbufInitS(&instance->config.logo.chafaSymbols, "block+border+space-wide-inverted"); // Chafa default - instance->config.logo.chafaCanvasMode = UINT32_MAX; - instance->config.logo.chafaColorSpace = UINT32_MAX; - instance->config.logo.chafaDitherMode = UINT32_MAX; + ffInitLogoOptions(&instance->config.logo); ffStrbufInit(&instance->config.colorKeys); ffStrbufInit(&instance->config.colorTitle); @@ -304,10 +289,8 @@ static void destroyModuleArg(FFModuleArgs* args) static void destroyConfig(FFinstance* instance) { - ffStrbufDestroy(&instance->config.logo.source); - ffStrbufDestroy(&instance->config.logo.chafaSymbols); - for(uint8_t i = 0; i < (uint8_t) FASTFETCH_LOGO_MAX_COLORS; ++i) - ffStrbufDestroy(&instance->config.logo.colors[i]); + ffDestroyLogoOptions(&instance->config.logo); + ffStrbufDestroy(&instance->config.colorKeys); ffStrbufDestroy(&instance->config.colorTitle); ffStrbufDestroy(&instance->config.keyValueSeparator); diff --git a/src/common/option.c b/src/common/option.c index 3f6c360e4..e151788be 100644 --- a/src/common/option.c +++ b/src/common/option.c @@ -14,6 +14,10 @@ const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName) return NULL; subKey += moduleNameLen; + + if(subKey[0] == '\0') + return subKey; + if(subKey[0] != '-') return NULL; @@ -101,6 +105,40 @@ bool ffOptionParseBoolean(const char* str) ); } +void ffOptionParseColor(const char* key, const char* value, FFstrbuf* buffer) +{ + if(value == NULL) + { + fprintf(stderr, "Error: usage: %s \n", key); + exit(477); + } + ffStrbufEnsureFree(buffer, 63); + + while(*value != '\0') + { + #define FF_APPEND_COLOR_CODE_COND(prefix, code) \ + if(strncasecmp(value, #prefix, strlen(#prefix))) { ffStrbufAppendS(buffer, code); value += strlen(#prefix); } + + FF_APPEND_COLOR_CODE_COND(reset_, "0;") + else FF_APPEND_COLOR_CODE_COND(bright_, "1;") + else FF_APPEND_COLOR_CODE_COND(black, "30") + else FF_APPEND_COLOR_CODE_COND(red, "31") + else FF_APPEND_COLOR_CODE_COND(green, "32") + else FF_APPEND_COLOR_CODE_COND(yellow, "33") + else FF_APPEND_COLOR_CODE_COND(blue, "34") + else FF_APPEND_COLOR_CODE_COND(magenta, "35") + else FF_APPEND_COLOR_CODE_COND(cyan, "36") + else FF_APPEND_COLOR_CODE_COND(white, "37") + else + { + ffStrbufAppendC(buffer, *value); + ++value; + } + + #undef FF_APPEND_COLOR_CODE_COND + } +} + void ffOptionInitModuleArg(FFModuleArgs* args) { ffStrbufInit(&args->key); diff --git a/src/common/option.h b/src/common/option.h index 1c56de4d3..0c8d29b1b 100644 --- a/src/common/option.h +++ b/src/common/option.h @@ -21,5 +21,6 @@ void ffOptionParseString(const char* argumentKey, const char* value, FFstrbuf* b FF_C_NODISCARD uint32_t ffOptionParseUInt32(const char* argumentKey, const char* value); FF_C_NODISCARD int ffOptionParseEnum(const char* argumentKey, const char* requestedKey, FFKeyValuePair pairs[]); FF_C_NODISCARD bool ffOptionParseBoolean(const char* str); +void ffOptionParseColor(const char* key, const char* value, FFstrbuf* buffer); void ffOptionInitModuleArg(FFModuleArgs* args); void ffOptionDestroyModuleArg(FFModuleArgs* args); diff --git a/src/fastfetch.c b/src/fastfetch.c index bc6528567..eb9ab31c9 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -5,6 +5,7 @@ #include "common/time.h" #include "util/FFvaluestore.h" #include "util/stringUtils.h" +#include "logo/logo.h" #include #include @@ -965,132 +966,7 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con //Logo options// //////////////// - else if(strcasecmp(key, "-l") == 0 || strcasecmp(key, "--logo") == 0) - { - optionParseString(key, value, &instance->config.logo.source); - - //this is usally wanted when using the none logo - if(strcasecmp(value, "none") == 0) - { - instance->config.logo.paddingTop = 0; - instance->config.logo.paddingRight = 0; - instance->config.logo.paddingLeft = 0; - instance->config.logo.type = FF_LOGO_TYPE_NONE; - } - } - else if(startsWith(key, "--logo")) - { - const char* subkey = key + strlen("--logo"); - if(strcasecmp(subkey, "-type") == 0) - { - optionParseEnum(key, value, &instance->config.logo.type, - "auto", FF_LOGO_TYPE_AUTO, - "builtin", FF_LOGO_TYPE_BUILTIN, - "file", FF_LOGO_TYPE_FILE, - "file-raw", FF_LOGO_TYPE_FILE_RAW, - "data", FF_LOGO_TYPE_DATA, - "data-raw", FF_LOGO_TYPE_DATA_RAW, - "sixel", FF_LOGO_TYPE_IMAGE_SIXEL, - "kitty", FF_LOGO_TYPE_IMAGE_KITTY, - "iterm", FF_LOGO_TYPE_IMAGE_ITERM, - "chafa", FF_LOGO_TYPE_IMAGE_CHAFA, - "raw", FF_LOGO_TYPE_IMAGE_RAW, - "none", FF_LOGO_TYPE_NONE, - NULL - ); - } - else if(startsWith(subkey, "-color-") && key[13] != '\0' && key[14] == '\0') // matches "--logo-color-*" - { - //Map the number to an array index, so that '1' -> 0, '2' -> 1, etc. - int index = (int)key[13] - 49; - - //Match only --logo-color-[1-9] - if(index < 0 || index >= FASTFETCH_LOGO_MAX_COLORS) - { - fprintf(stderr, "Error: invalid --color-[1-9] index: %c\n", key[13]); - exit(472); - } - - optionParseColor(key, value, &instance->config.logo.colors[index]); - } - else if(strcasecmp(subkey, "-width") == 0) - instance->config.logo.width = optionParseUInt32(key, value); - else if(strcasecmp(subkey, "-height") == 0) - instance->config.logo.height = optionParseUInt32(key, value); - else if(strcasecmp(subkey, "-padding") == 0) - { - uint32_t padding = optionParseUInt32(key, value); - instance->config.logo.paddingLeft = padding; - instance->config.logo.paddingRight = padding; - } - else if(strcasecmp(subkey, "-padding-top") == 0) - instance->config.logo.paddingTop = optionParseUInt32(key, value); - else if(strcasecmp(subkey, "-padding-left") == 0) - instance->config.logo.paddingLeft = optionParseUInt32(key, value); - else if(strcasecmp(subkey, "-padding-right") == 0) - instance->config.logo.paddingRight = optionParseUInt32(key, value); - else if(strcasecmp(subkey, "-print-remaining") == 0) - instance->config.logo.printRemaining = optionParseBoolean(value); - else if(strcasecmp(subkey, "-preserve-aspect-radio") == 0) - instance->config.logo.preserveAspectRadio = optionParseBoolean(value); - else - goto error; - } - else if(strcasecmp(key, "--file") == 0) - { - optionParseString(key, value, &instance->config.logo.source); - instance->config.logo.type = FF_LOGO_TYPE_FILE; - } - else if(strcasecmp(key, "--file-raw") == 0) - { - optionParseString(key, value, &instance->config.logo.source); - instance->config.logo.type = FF_LOGO_TYPE_FILE_RAW; - } - else if(strcasecmp(key, "--data") == 0) - { - optionParseString(key, value, &instance->config.logo.source); - instance->config.logo.type = FF_LOGO_TYPE_DATA; - } - else if(strcasecmp(key, "--data-raw") == 0) - { - optionParseString(key, value, &instance->config.logo.source); - instance->config.logo.type = FF_LOGO_TYPE_DATA_RAW; - } - else if(strcasecmp(key, "--sixel") == 0) - { - optionParseString(key, value, &instance->config.logo.source); - instance->config.logo.type = FF_LOGO_TYPE_IMAGE_SIXEL; - } - else if(strcasecmp(key, "--kitty") == 0) - { - optionParseString(key, value, &instance->config.logo.source); - instance->config.logo.type = FF_LOGO_TYPE_IMAGE_KITTY; - } - else if(strcasecmp(key, "--chafa") == 0) - { - optionParseString(key, value, &instance->config.logo.source); - instance->config.logo.type = FF_LOGO_TYPE_IMAGE_CHAFA; - } - else if(strcasecmp(key, "--iterm") == 0) - { - optionParseString(key, value, &instance->config.logo.source); - instance->config.logo.type = FF_LOGO_TYPE_IMAGE_ITERM; - } - else if(strcasecmp(key, "--raw") == 0) - { - optionParseString(key, value, &instance->config.logo.source); - instance->config.logo.type = FF_LOGO_TYPE_IMAGE_RAW; - } - else if(strcasecmp(key, "--chafa-fg-only") == 0) - instance->config.logo.chafaFgOnly = optionParseBoolean(value); - else if(strcasecmp(key, "--chafa-symbols") == 0) - optionParseString(key, value, &instance->config.logo.chafaSymbols); - else if(strcasecmp(key, "--chafa-canvas-mode") == 0) - instance->config.logo.chafaCanvasMode = optionParseUInt32(key, value); - else if(strcasecmp(key, "--chafa-color-space") == 0) - instance->config.logo.chafaColorSpace = optionParseUInt32(key, value); - else if(strcasecmp(key, "--chafa-dither-mode") == 0) - instance->config.logo.chafaDitherMode = optionParseUInt32(key, value); + else if(ffParseLogoCommandOptions(&instance->config.logo, key, value)) {} /////////////////// //Display options// diff --git a/src/fastfetch.h b/src/fastfetch.h index 79dd8a0f3..3453f3bd5 100644 --- a/src/fastfetch.h +++ b/src/fastfetch.h @@ -16,25 +16,8 @@ static inline void ffUnused(int dummy, ...) { (void) dummy; } #define FF_UNUSED(...) ffUnused(0, __VA_ARGS__); #define FF_MAYBE_UNUSED __attribute__ ((__unused__)) -#define FASTFETCH_LOGO_MAX_COLORS 9 //two digits would make parsing much more complicated (index 1 - 9) - #include "modules/options.h" - -typedef enum FFLogoType -{ - FF_LOGO_TYPE_AUTO, //if something is given, first try builtin, then file. Otherwise detect logo - FF_LOGO_TYPE_BUILTIN, //builtin ascii art - FF_LOGO_TYPE_FILE, //text file, printed with color code replacement - FF_LOGO_TYPE_FILE_RAW, //text file, printed as is - FF_LOGO_TYPE_DATA, //text data, printed with color code replacement - FF_LOGO_TYPE_DATA_RAW, //text data, printed as is - FF_LOGO_TYPE_IMAGE_SIXEL, //image file, printed as sixel codes. - FF_LOGO_TYPE_IMAGE_KITTY, //image file, printed as kitty graphics protocol - FF_LOGO_TYPE_IMAGE_ITERM, //image file, printed as iterm graphics protocol - FF_LOGO_TYPE_IMAGE_CHAFA, //image file, printed as ascii art using libchafa - FF_LOGO_TYPE_IMAGE_RAW, //image file, printed as raw binary string - FF_LOGO_TYPE_NONE, //--logo none -} FFLogoType; +#include "logo/option.h" typedef enum FFSoundType { @@ -88,25 +71,7 @@ typedef enum FFLocalIpType typedef struct FFconfig { - struct - { - FFstrbuf source; - FFLogoType type; - FFstrbuf colors[FASTFETCH_LOGO_MAX_COLORS]; - uint32_t width; - uint32_t height; - uint32_t paddingTop; - uint32_t paddingLeft; - uint32_t paddingRight; - bool printRemaining; - bool preserveAspectRadio; - - bool chafaFgOnly; - FFstrbuf chafaSymbols; - uint32_t chafaCanvasMode; - uint32_t chafaColorSpace; - uint32_t chafaDitherMode; - } logo; + FFLogoOptions logo; //If one of those is empty, ffLogoPrint will set them FFstrbuf colorKeys; @@ -230,6 +195,8 @@ typedef struct FFconfig FFstrbuf playerName; uint32_t percentType; + + bool jsonConfig; } FFconfig; typedef struct FFstate diff --git a/src/logo/logo.c b/src/logo/logo.c index 43d39bc97..4b7fa2124 100644 --- a/src/logo/logo.c +++ b/src/logo/logo.c @@ -1,4 +1,4 @@ -#include "logo.h" +#include "logo/logo.h" #include "common/io/io.h" #include "common/printing.h" #include "detection/os/os.h" @@ -10,35 +10,38 @@ static void ffLogoPrintCharsRaw(FFinstance* instance, const char* data, size_t length) { + FFLogoOptions* options = &instance->config.logo; fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout); - ffPrintCharTimes('\n', instance->config.logo.paddingTop); - ffPrintCharTimes(' ', instance->config.logo.paddingLeft); + ffPrintCharTimes('\n', options->paddingTop); + ffPrintCharTimes(' ', options->paddingLeft); fwrite(data, length, 1, stdout); - instance->state.logoHeight = instance->config.logo.paddingTop + instance->config.logo.height; - instance->state.logoWidth = instance->config.logo.paddingLeft + instance->config.logo.width + instance->config.logo.paddingRight; + instance->state.logoHeight = options->paddingTop + options->height; + instance->state.logoWidth = options->paddingLeft + options->width + options->paddingRight; printf("\033[9999999D\n\033[%uA", instance->state.logoHeight); } void ffLogoPrintChars(FFinstance* instance, const char* data, bool doColorReplacement) { + FFLogoOptions* options = &instance->config.logo; + uint32_t currentlineLength = 0; fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout); - ffPrintCharTimes('\n', instance->config.logo.paddingTop); - ffPrintCharTimes(' ', instance->config.logo.paddingLeft); + ffPrintCharTimes('\n', options->paddingTop); + ffPrintCharTimes(' ', options->paddingLeft); - instance->state.logoHeight = instance->config.logo.paddingTop; + instance->state.logoHeight = options->paddingTop; //Use logoColor[0] as the default color if(doColorReplacement) - ffPrintColor(&instance->config.logo.colors[0]); + ffPrintColor(&options->colors[0]); while(*data != '\0') { //We are at the end of a line. Print paddings and update max line length if(*data == '\n' || (*data == '\r' && *(data + 1) == '\n')) { - ffPrintCharTimes(' ', instance->config.logo.paddingRight); + ffPrintCharTimes(' ', options->paddingRight); //We have \r\n, skip the \r if(*data == '\r') @@ -47,7 +50,7 @@ void ffLogoPrintChars(FFinstance* instance, const char* data, bool doColorReplac putchar('\n'); ++data; - ffPrintCharTimes(' ', instance->config.logo.paddingLeft); + ffPrintCharTimes(' ', options->paddingLeft); if(currentlineLength > instance->state.logoWidth) instance->state.logoWidth = currentlineLength; @@ -115,7 +118,7 @@ void ffLogoPrintChars(FFinstance* instance, const char* data, bool doColorReplac } else { - ffPrintColor(&instance->config.logo.colors[index]); + ffPrintColor(&options->colors[index]); ++data; continue; } @@ -148,14 +151,14 @@ void ffLogoPrintChars(FFinstance* instance, const char* data, bool doColorReplac } } - ffPrintCharTimes(' ', instance->config.logo.paddingRight); + ffPrintCharTimes(' ', options->paddingRight); fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout); //Happens if the last line is the longest if(currentlineLength > instance->state.logoWidth) instance->state.logoWidth = currentlineLength; - instance->state.logoWidth += instance->config.logo.paddingLeft + instance->config.logo.paddingRight; + instance->state.logoWidth += options->paddingLeft + options->paddingRight; //Go to the leftmost position fputs("\033[9999999D", stdout); @@ -241,11 +244,13 @@ static void logoPrintStruct(FFinstance* instance, const FFlogo* logo) { logoApplyColors(instance, logo); + FFLogoOptions* options = &instance->config.logo; + const char** colors = logo->builtinColors; for(int i = 0; *colors != NULL && i < FASTFETCH_LOGO_MAX_COLORS; i++, colors++) { - if(instance->config.logo.colors[i].length == 0) - ffStrbufAppendS(&instance->config.logo.colors[i], *colors); + if(options->colors[i].length == 0) + ffStrbufAppendS(&options->colors[i], *colors); } ffLogoPrintChars(instance, logo->data, true); @@ -281,17 +286,20 @@ static inline void logoPrintDetected(FFinstance* instance) } static bool logoPrintData(FFinstance* instance, bool doColorReplacement) { - if(instance->config.logo.source.length == 0) + FFLogoOptions* options = &instance->config.logo; + if(options->source.length == 0) return false; - ffLogoPrintChars(instance, instance->config.logo.source.chars, doColorReplacement); + ffLogoPrintChars(instance, options->source.chars, doColorReplacement); logoApplyColorsDetected(instance); return true; } static void updateLogoPath(FFinstance* instance) { - if(ffPathExists(instance->config.logo.source.chars, FF_PATHTYPE_FILE)) + FFLogoOptions* options = &instance->config.logo; + + if(ffPathExists(options->source.chars, FF_PATHTYPE_FILE)) return; FFstrbuf fullPath; @@ -302,11 +310,11 @@ static void updateLogoPath(FFinstance* instance) //We need to copy it, because multiple threads might be using dataDirs at the same time ffStrbufSet(&fullPath, dataDir); ffStrbufAppendS(&fullPath, "fastfetch/logos/"); - ffStrbufAppend(&fullPath, &instance->config.logo.source); + ffStrbufAppend(&fullPath, &options->source); if(ffPathExists(fullPath.chars, FF_PATHTYPE_FILE)) { - ffStrbufSet(&instance->config.logo.source, &fullPath); + ffStrbufSet(&options->source, &fullPath); break; } } @@ -316,10 +324,12 @@ static void updateLogoPath(FFinstance* instance) static bool logoPrintFileIfExists(FFinstance* instance, bool doColorReplacement, bool raw) { - FFstrbuf content; + FFLogoOptions* options = &instance->config.logo; + + FF_STRBUF_AUTO_DESTROY content; ffStrbufInit(&content); - if(!ffAppendFileBuffer(instance->config.logo.source.chars, &content)) + if(!ffAppendFileBuffer(options->source.chars, &content)) { ffStrbufDestroy(&content); fputs("Logo: Failed to load file content from logo source\n", stderr); @@ -331,7 +341,6 @@ static bool logoPrintFileIfExists(FFinstance* instance, bool doColorReplacement, ffLogoPrintCharsRaw(instance, content.chars, content.length); else ffLogoPrintChars(instance, content.chars, doColorReplacement); - ffStrbufDestroy(&content); return true; } @@ -346,32 +355,34 @@ static bool logoPrintImageIfExists(FFinstance* instance, FFLogoType logo, bool p static bool logoTryKnownType(FFinstance* instance) { - if(instance->config.logo.type == FF_LOGO_TYPE_NONE) + FFLogoOptions* options = &instance->config.logo; + + if(options->type == FF_LOGO_TYPE_NONE) { logoApplyColorsDetected(instance); return true; } - if(instance->config.logo.type == FF_LOGO_TYPE_BUILTIN) - return logoPrintBuiltinIfExists(instance, instance->config.logo.source.chars); + if(options->type == FF_LOGO_TYPE_BUILTIN) + return logoPrintBuiltinIfExists(instance, options->source.chars); - if(instance->config.logo.type == FF_LOGO_TYPE_DATA) + if(options->type == FF_LOGO_TYPE_DATA) return logoPrintData(instance, true); - if(instance->config.logo.type == FF_LOGO_TYPE_DATA_RAW) + if(options->type == FF_LOGO_TYPE_DATA_RAW) return logoPrintData(instance, false); updateLogoPath(instance); //We sure have a file, resolve relative paths - if(instance->config.logo.type == FF_LOGO_TYPE_FILE) + if(options->type == FF_LOGO_TYPE_FILE) return logoPrintFileIfExists(instance, true, false); - if(instance->config.logo.type == FF_LOGO_TYPE_FILE_RAW) + if(options->type == FF_LOGO_TYPE_FILE_RAW) return logoPrintFileIfExists(instance, false, false); - if(instance->config.logo.type == FF_LOGO_TYPE_IMAGE_RAW) + if(options->type == FF_LOGO_TYPE_IMAGE_RAW) { - if(instance->config.logo.width == 0 || instance->config.logo.height == 0) + if(options->width == 0 || options->height == 0) { fputs("both `--logo-width` and `--logo-height` must be specified\n", stderr); return false; @@ -380,7 +391,7 @@ static bool logoTryKnownType(FFinstance* instance) return logoPrintFileIfExists(instance, false, true); } - return logoPrintImageIfExists(instance, instance->config.logo.type, true); + return logoPrintImageIfExists(instance, options->type, true); } static void logoPrintKnownType(FFinstance* instance) @@ -401,22 +412,24 @@ void ffLogoPrint(FFinstance* instance) return; } + const FFLogoOptions* options = &instance->config.logo; + //If the source is not set, we can directly print the detected logo. - if(instance->config.logo.source.length == 0) + if(options->source.length == 0) { logoPrintDetected(instance); return; } //If the source and source type is set to something else than auto, always print with the set type. - if(instance->config.logo.source.length > 0 && instance->config.logo.type != FF_LOGO_TYPE_AUTO) + if(options->source.length > 0 && options->type != FF_LOGO_TYPE_AUTO) { logoPrintKnownType(instance); return; } //If source matches the name of a builtin logo, print it and return. - if(logoPrintBuiltinIfExists(instance, instance->config.logo.source.chars)) + if(logoPrintBuiltinIfExists(instance, options->source.chars)) return; //Make sure the logo path is set correctly. @@ -462,6 +475,7 @@ void ffLogoPrintRemaining(FFinstance* instance) void ffLogoBuiltinPrint(FFinstance* instance) { GetLogoMethod* methods = ffLogoBuiltinGetAll(); + FFLogoOptions* options = &instance->config.logo; while(*methods != NULL) { @@ -474,7 +488,7 @@ void ffLogoBuiltinPrint(FFinstance* instance) instance->state.logoHeight = 0; instance->state.keysHeight = 0; for(uint8_t i = 0; i < FASTFETCH_LOGO_MAX_COLORS; i++) - ffStrbufClear(&instance->config.logo.colors[i]); + ffStrbufClear(&options->colors[i]); puts("\n"); ++methods; diff --git a/src/logo/logo.h b/src/logo/logo.h index 0664f6f98..9d3878c66 100644 --- a/src/logo/logo.h +++ b/src/logo/logo.h @@ -26,4 +26,9 @@ GetLogoMethod* ffLogoBuiltinGetAll(); //image/image.c bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type, bool printError); +//option.c +void ffInitLogoOptions(FFLogoOptions* options); +bool ffParseLogoCommandOptions(FFLogoOptions* options, const char* key, const char* value); +void ffDestroyLogoOptions(FFLogoOptions* options); + #endif diff --git a/src/logo/option.c b/src/logo/option.c new file mode 100644 index 000000000..033885635 --- /dev/null +++ b/src/logo/option.c @@ -0,0 +1,183 @@ +#include "logo/logo.h" + +void ffInitLogoOptions(FFLogoOptions* options) +{ + ffStrbufInit(&options->source); + options->type = FF_LOGO_TYPE_AUTO; + for(uint8_t i = 0; i < (uint8_t) FASTFETCH_LOGO_MAX_COLORS; ++i) + ffStrbufInit(&options->colors[i]); + options->width = 0; + options->height = 0; //preserve aspect ratio + options->paddingTop = 0; + options->paddingLeft = 0; + options->paddingRight = 4; + options->printRemaining = true; + options->preserveAspectRadio = false; + + options->chafaFgOnly = false; + ffStrbufInitS(&options->chafaSymbols, "block+border+space-wide-inverted"); // Chafa default + options->chafaCanvasMode = UINT32_MAX; + options->chafaColorSpace = UINT32_MAX; + options->chafaDitherMode = UINT32_MAX; +} + +bool ffParseLogoCommandOptions(FFLogoOptions* options, const char* key, const char* value) +{ + if (strcasecmp(key, "-l") == 0) + goto logoType; + + const char* subKey = ffOptionTestPrefix(key, "logo"); + if(subKey) + { + if (subKey[0] == '\0') + { +logoType: + ffOptionParseString(key, value, &options->source); + + //this is usally wanted when using the none logo + if(strcasecmp(value, "none") == 0) + { + options->paddingTop = 0; + options->paddingRight = 0; + options->paddingLeft = 0; + options->type = FF_LOGO_TYPE_NONE; + } + } + else if(strcasecmp(subKey, "type") == 0) + { + options->type = (FFLogoType) ffOptionParseEnum(key, value, (FFKeyValuePair[]) { + { "auto", FF_LOGO_TYPE_AUTO }, + { "builtin", FF_LOGO_TYPE_BUILTIN }, + { "file", FF_LOGO_TYPE_FILE }, + { "file-raw", FF_LOGO_TYPE_FILE_RAW }, + { "data", FF_LOGO_TYPE_DATA }, + { "data-raw", FF_LOGO_TYPE_DATA_RAW }, + { "sixel", FF_LOGO_TYPE_IMAGE_SIXEL }, + { "kitty", FF_LOGO_TYPE_IMAGE_KITTY }, + { "iterm", FF_LOGO_TYPE_IMAGE_ITERM }, + { "chafa", FF_LOGO_TYPE_IMAGE_CHAFA }, + { "raw", FF_LOGO_TYPE_IMAGE_RAW }, + { "none", FF_LOGO_TYPE_NONE }, + {}, + }); + } + else if(strncasecmp(subKey, "color-", strlen("color-")) && key[13] != '\0' && key[14] == '\0') // matches "--logo-color-*" + { + //Map the number to an array index, so that '1' -> 0, '2' -> 1, etc. + int index = (int)key[13] - 49; + + //Match only --logo-color-[1-9] + if(index < 0 || index >= FASTFETCH_LOGO_MAX_COLORS) + { + fprintf(stderr, "Error: invalid --color-[1-9] index: %c\n", key[13]); + exit(472); + } + + ffOptionParseColor(key, value, &options->colors[index]); + } + else if(strcasecmp(subKey, "width") == 0) + options->width = ffOptionParseUInt32(key, value); + else if(strcasecmp(subKey, "height") == 0) + options->height = ffOptionParseUInt32(key, value); + else if(strcasecmp(subKey, "padding") == 0) + { + uint32_t padding = ffOptionParseUInt32(key, value); + options->paddingLeft = padding; + options->paddingRight = padding; + } + else if(strcasecmp(subKey, "padding-top") == 0) + options->paddingTop = ffOptionParseUInt32(key, value); + else if(strcasecmp(subKey, "padding-left") == 0) + options->paddingLeft = ffOptionParseUInt32(key, value); + else if(strcasecmp(subKey, "padding-right") == 0) + options->paddingRight = ffOptionParseUInt32(key, value); + else if(strcasecmp(subKey, "print-remaining") == 0) + options->printRemaining = ffOptionParseBoolean(value); + else if(strcasecmp(subKey, "preserve-aspect-radio") == 0) + options->preserveAspectRadio = ffOptionParseBoolean(value); + else + return false; + } + else if((subKey = ffOptionTestPrefix(key, "file"))) + { + if(subKey[0] == '\0') + { + ffOptionParseString(key, value, &options->source); + options->type = FF_LOGO_TYPE_FILE; + } + else if(strcasecmp(key, "raw") == 0) + { + ffOptionParseString(key, value, &options->source); + options->type = FF_LOGO_TYPE_FILE_RAW; + } + else + return false; + } + else if((subKey = ffOptionTestPrefix(key, "data"))) + { + if(subKey[0] == '\0') + { + ffOptionParseString(key, value, &options->source); + options->type = FF_LOGO_TYPE_DATA; + } + else if(strcasecmp(subKey, "raw") == 0) + { + ffOptionParseString(key, value, &options->source); + options->type = FF_LOGO_TYPE_DATA_RAW; + } + else + return false; + } + else if(strcasecmp(key, "--sixel") == 0) + { + ffOptionParseString(key, value, &options->source); + options->type = FF_LOGO_TYPE_IMAGE_SIXEL; + } + else if(strcasecmp(key, "--kitty") == 0) + { + ffOptionParseString(key, value, &options->source); + options->type = FF_LOGO_TYPE_IMAGE_KITTY; + } + else if(strcasecmp(key, "--iterm") == 0) + { + ffOptionParseString(key, value, &options->source); + options->type = FF_LOGO_TYPE_IMAGE_ITERM; + } + else if(strcasecmp(key, "--raw") == 0) + { + ffOptionParseString(key, value, &options->source); + options->type = FF_LOGO_TYPE_IMAGE_RAW; + } + else if((subKey = ffOptionTestPrefix(key, "chafa"))) + { + if(subKey[0] == '\0') + { + ffOptionParseString(key, value, &options->source); + options->type = FF_LOGO_TYPE_IMAGE_CHAFA; + } + else if(strcasecmp(subKey, "fg-only") == 0) + options->chafaFgOnly = ffOptionParseBoolean(value); + else if(strcasecmp(subKey, "symbols") == 0) + ffOptionParseString(key, value, &options->chafaSymbols); + else if(strcasecmp(subKey, "canvas-mode") == 0) + options->chafaCanvasMode = ffOptionParseUInt32(key, value); + else if(strcasecmp(subKey, "color-space") == 0) + options->chafaColorSpace = ffOptionParseUInt32(key, value); + else if(strcasecmp(subKey, "dither-mode") == 0) + options->chafaDitherMode = ffOptionParseUInt32(key, value); + else + return false; + } + else + return false; + + return true; +} + +void ffDestroyLogoOptions(FFLogoOptions* options) +{ + ffStrbufDestroy(&options->source); + ffStrbufDestroy(&options->chafaSymbols); + for(uint8_t i = 0; i < (uint8_t) FASTFETCH_LOGO_MAX_COLORS; ++i) + ffStrbufDestroy(&options->colors[i]); +} diff --git a/src/logo/option.h b/src/logo/option.h new file mode 100644 index 000000000..09f7822d1 --- /dev/null +++ b/src/logo/option.h @@ -0,0 +1,41 @@ +#pragma once + +#include "util/FFstrbuf.h" + +#define FASTFETCH_LOGO_MAX_COLORS 9 //two digits would make parsing much more complicated (index 1 - 9) + +typedef enum FFLogoType +{ + FF_LOGO_TYPE_AUTO, //if something is given, first try builtin, then file. Otherwise detect logo + FF_LOGO_TYPE_BUILTIN, //builtin ascii art + FF_LOGO_TYPE_FILE, //text file, printed with color code replacement + FF_LOGO_TYPE_FILE_RAW, //text file, printed as is + FF_LOGO_TYPE_DATA, //text data, printed with color code replacement + FF_LOGO_TYPE_DATA_RAW, //text data, printed as is + FF_LOGO_TYPE_IMAGE_SIXEL, //image file, printed as sixel codes. + FF_LOGO_TYPE_IMAGE_KITTY, //image file, printed as kitty graphics protocol + FF_LOGO_TYPE_IMAGE_ITERM, //image file, printed as iterm graphics protocol + FF_LOGO_TYPE_IMAGE_CHAFA, //image file, printed as ascii art using libchafa + FF_LOGO_TYPE_IMAGE_RAW, //image file, printed as raw binary string + FF_LOGO_TYPE_NONE, //--logo none +} FFLogoType; + +typedef struct FFLogoOptions +{ + FFstrbuf source; + FFLogoType type; + FFstrbuf colors[FASTFETCH_LOGO_MAX_COLORS]; + uint32_t width; + uint32_t height; + uint32_t paddingTop; + uint32_t paddingLeft; + uint32_t paddingRight; + bool printRemaining; + bool preserveAspectRadio; + + bool chafaFgOnly; + FFstrbuf chafaSymbols; + uint32_t chafaCanvasMode; + uint32_t chafaColorSpace; + uint32_t chafaDitherMode; +} FFLogoOptions;