mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2025-02-20 11:43:27 +08:00
Logo: move logo command line option parser to a separate file
Prepare for JSON config support
This commit is contained in:
parent
ae08966d40
commit
e812380f20
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
128
src/fastfetch.c
128
src/fastfetch.c
@ -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//
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
183
src/logo/option.c
Normal 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
41
src/logo/option.h
Normal 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;
|
Loading…
x
Reference in New Issue
Block a user