Logo: move logo command line option parser to a separate file

Prepare for JSON config support
This commit is contained in:
李通洲 2023-03-10 17:49:03 +08:00
parent ae08966d40
commit e812380f20
10 changed files with 331 additions and 222 deletions

View File

@ -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

View File

@ -3,6 +3,7 @@
#include "common/thread.h"
#include "detection/displayserver/displayserver.h"
#include "util/textModifier.h"
#include "logo/logo.h"
#include <stdlib.h>
#include <unistd.h>
@ -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);

View File

@ -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 <str>\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);

View File

@ -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);

View File

@ -5,6 +5,7 @@
#include "common/time.h"
#include "util/FFvaluestore.h"
#include "util/stringUtils.h"
#include "logo/logo.h"
#include <stdlib.h>
#include <ctype.h>
@ -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//

View File

@ -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

View File

@ -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;

View File

@ -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

183
src/logo/option.c Normal file
View File

@ -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]);
}

41
src/logo/option.h Normal file
View File

@ -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;