From d3453de73ccf971da4ad049486bccdb0f995fc3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 15 Jan 2026 15:03:38 +0800 Subject: [PATCH] Global: puts more fastfetch-only properties into `FFdata` --- src/common/FFPlatform.h | 2 +- src/common/commandoption.h | 14 +--- src/common/ffdata.h | 24 ++++++ src/common/impl/commandoption.c | 31 ++++---- src/common/impl/init.c | 13 +-- src/common/impl/jsonconfig.c | 10 ++- src/common/jsonconfig.h | 8 +- src/fastfetch.c | 137 +++++++++++++++++--------------- src/fastfetch.h | 13 +-- src/flashfetch.c | 5 +- src/logo/logo.c | 13 +-- src/options/display.c | 3 +- src/options/display.h | 3 +- src/options/general.c | 3 +- src/options/general.h | 4 +- src/options/logo.c | 3 +- src/options/logo.h | 38 ++++----- 17 files changed, 168 insertions(+), 156 deletions(-) create mode 100644 src/common/ffdata.h diff --git a/src/common/FFPlatform.h b/src/common/FFPlatform.h index bf3af7856..2962cbd17 100644 --- a/src/common/FFPlatform.h +++ b/src/common/FFPlatform.h @@ -18,7 +18,7 @@ typedef struct FFPlatform FFstrbuf cacheDir; // Trailing slash included FFlist configDirs; // List of FFstrbuf, trailing slash included FFlist dataDirs; // List of FFstrbuf, trailing slash included - FFstrbuf exePath; // The real path of current exe + FFstrbuf exePath; // The real path of current exe (empty if unavailable) FFstrbuf userName; FFstrbuf fullUserName; diff --git a/src/common/commandoption.h b/src/common/commandoption.h index c8f7aae3b..5f64701b0 100644 --- a/src/common/commandoption.h +++ b/src/common/commandoption.h @@ -1,16 +1,8 @@ #pragma once -#include "fastfetch.h" - -// Things only needed by fastfetch -typedef struct FFdata -{ - FFstrbuf structure; - FFstrbuf structureDisabled; - bool configLoaded; -} FFdata; +#include "common/ffdata.h" void ffPrepareCommandOption(FFdata* data); -void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc); -void ffMigrateCommandOptionToJsonc(FFdata* data, yyjson_mut_doc* jsonDoc); +void ffPrintCommandOption(FFdata* data); +void ffMigrateCommandOptionToJsonc(FFdata* data); bool ffParseModuleOptions(const char* key, const char* value); diff --git a/src/common/ffdata.h b/src/common/ffdata.h new file mode 100644 index 000000000..51b401ff3 --- /dev/null +++ b/src/common/ffdata.h @@ -0,0 +1,24 @@ +#pragma once + +#include "common/FFstrbuf.h" + +typedef enum __attribute__((__packed__)) FFDataResultDocType +{ + FF_RESULT_DOC_TYPE_DEFAULT = 0, + FF_RESULT_DOC_TYPE_JSON, + FF_RESULT_DOC_TYPE_CONFIG, + FF_RESULT_DOC_TYPE_CONFIG_FULL, +} FFDataResultDocType; + +// FFdata aggregates configuration, generation parameters, and output state used by fastfetch. +// It holds the parsed configuration document, a mutable JSON document for results, and related metadata. +typedef struct FFdata +{ + yyjson_doc* configDoc; // Parsed JSON configuration document + yyjson_mut_doc* resultDoc; // Mutable JSON document for storing results + FFstrbuf structure; // Custom output structure from command line + FFstrbuf structureDisabled; // Disabled modules in the output structure from command line + FFstrbuf genConfigPath; // Path to generate configuration file + FFDataResultDocType docType; // Type of result document + bool configLoaded; +} FFdata; diff --git a/src/common/impl/commandoption.c b/src/common/impl/commandoption.c index 56493fa02..7cfe65349 100644 --- a/src/common/impl/commandoption.c +++ b/src/common/impl/commandoption.c @@ -127,8 +127,10 @@ void ffPrepareCommandOption(FFdata* data) } } -static void genJsonConfig(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* doc) +static void genJsonConfig(FFdata* data, FFModuleBaseInfo* baseInfo, void* options) { + yyjson_mut_doc* doc = data->resultDoc; + yyjson_mut_val* modules = yyjson_mut_obj_get(doc->root, "modules"); if (!modules) modules = yyjson_mut_obj_add_arr(doc, doc->root, "modules"); @@ -136,7 +138,7 @@ static void genJsonConfig(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_ FF_STRBUF_AUTO_DESTROY type = ffStrbufCreateS(baseInfo->name); ffStrbufLowerCase(&type); - if (instance.state.fullConfig) + if (data->docType == FF_RESULT_DOC_TYPE_CONFIG_FULL) { yyjson_mut_val* module = yyjson_mut_obj(doc); yyjson_mut_obj_add_strbuf(doc, module, "type", &type); @@ -155,8 +157,9 @@ static void genJsonConfig(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_ } } -static void genJsonResult(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* doc) +static void genJsonResult(FFdata* data, FFModuleBaseInfo* baseInfo, void* options) { + yyjson_mut_doc* doc = data->resultDoc; yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root); yyjson_mut_obj_add_str(doc, module, "type", baseInfo->name); if (baseInfo->generateJsonResult) @@ -166,9 +169,9 @@ static void genJsonResult(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_ } static void parseStructureCommand( + FFdata* data, const char* line, - void (*fn)(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* jsonDoc), - yyjson_mut_doc* jsonDoc + void (*fn)(FFdata*, FFModuleBaseInfo* baseInfo, void* options) ) { if(ffCharIsEnglishAlphabet(line[0])) @@ -180,8 +183,8 @@ static void parseStructureCommand( { uint8_t optionBuf[FF_OPTION_MAX_SIZE]; baseInfo->initOptions(optionBuf); - if (__builtin_expect(jsonDoc != NULL, false)) - fn(baseInfo, optionBuf, jsonDoc); + if (__builtin_expect(data->resultDoc != NULL, false)) + fn(data, baseInfo, optionBuf); else baseInfo->printModule(optionBuf); baseInfo->destroyOptions(optionBuf); @@ -193,7 +196,7 @@ static void parseStructureCommand( ffPrintError(line, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, ""); } -void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc) +void ffPrintCommandOption(FFdata* data) { //Parse the structure and call the modules int32_t thres = instance.config.display.stat; @@ -209,16 +212,16 @@ void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc) if(thres >= 0) ms = ffTimeGetTick(); - parseStructureCommand(moduleType, genJsonResult, jsonDoc); + parseStructureCommand(data, moduleType, genJsonResult); if(thres >= 0) { ms = ffTimeGetTick() - ms; - if (jsonDoc) + if (data->resultDoc) { - yyjson_mut_val* moduleJson = yyjson_mut_arr_get_last(jsonDoc->root); - yyjson_mut_obj_add_real(jsonDoc, moduleJson, "stat", ms); + yyjson_mut_val* moduleJson = yyjson_mut_arr_get_last(data->resultDoc->root); + yyjson_mut_obj_add_real(data->resultDoc, moduleJson, "stat", ms); } else { @@ -236,7 +239,7 @@ void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc) } } -void ffMigrateCommandOptionToJsonc(FFdata* data, yyjson_mut_doc* jsonDoc) +void ffMigrateCommandOptionToJsonc(FFdata* data) { //If we don't have a custom structure, use the default one if(data->structure.length == 0) @@ -249,6 +252,6 @@ void ffMigrateCommandOptionToJsonc(FFdata* data, yyjson_mut_doc* jsonDoc) if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleType, ':')) continue; - parseStructureCommand(moduleType, genJsonConfig, jsonDoc); + parseStructureCommand(data, moduleType, genJsonConfig); } } diff --git a/src/common/impl/init.c b/src/common/impl/init.c index ae28316d6..ab9d0ad53 100644 --- a/src/common/impl/init.c +++ b/src/common/impl/init.c @@ -28,8 +28,6 @@ static void initState(FFstate* state) state->titleFqdn = false; ffPlatformInit(&state->platform); - state->configDoc = NULL; - state->resultDoc = NULL; state->dynamicInterval = 0; { @@ -96,8 +94,8 @@ static void exitSignalHandler(FF_MAYBE_UNUSED int signal) void ffStart(void) { - ffDisableLinewrap = instance.config.display.disableLinewrap && !instance.config.display.pipe && !instance.state.resultDoc; - ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe && !instance.state.resultDoc; + ffDisableLinewrap = instance.config.display.disableLinewrap && !instance.config.display.pipe; + ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe; #ifdef _WIN32 SetErrorMode(SEM_FAILCRITICALERRORS); @@ -124,7 +122,7 @@ void ffStart(void) #endif //reset everything to default before we start printing - if(!instance.config.display.pipe && !instance.state.resultDoc) + if(!instance.config.display.pipe) fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout); if(ffHideCursor) @@ -138,8 +136,6 @@ void ffStart(void) fputs("\033[?1049h\033[H", stdout); // Enable alternate buffer fflush(stdout); } - - ffLogoPrint(); } void ffFinish(void) @@ -157,9 +153,6 @@ static void destroyConfig(void) static void destroyState(void) { ffPlatformDestroy(&instance.state.platform); - yyjson_doc_free(instance.state.configDoc); - yyjson_mut_doc_free(instance.state.resultDoc); - ffStrbufDestroy(&instance.state.genConfigPath); } void ffDestroyInstance(void) diff --git a/src/common/impl/jsonconfig.c b/src/common/impl/jsonconfig.c index f1e270b48..7496bbbac 100644 --- a/src/common/impl/jsonconfig.c +++ b/src/common/impl/jsonconfig.c @@ -230,9 +230,10 @@ static bool matchesJsonArray(const char* str, yyjson_val* val) return false; } -static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc) +static const char* printJsonConfig(FFdata* data, bool prepare) { - yyjson_val* const root = yyjson_doc_get_root(instance.state.configDoc); + yyjson_mut_doc* jsonDoc = data->resultDoc; + yyjson_val* const root = yyjson_doc_get_root(data->configDoc); assert(root); if (!yyjson_is_obj(root)) @@ -329,9 +330,10 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc) return NULL; } -void ffPrintJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc) +void ffPrintJsonConfig(FFdata* data, bool prepare) { - const char* error = printJsonConfig(prepare, jsonDoc); + yyjson_mut_doc* jsonDoc = data->resultDoc; + const char* error = printJsonConfig(data, prepare); if (error) { if (jsonDoc) diff --git a/src/common/jsonconfig.h b/src/common/jsonconfig.h index 08a297f75..55f9ab5f8 100644 --- a/src/common/jsonconfig.h +++ b/src/common/jsonconfig.h @@ -1,11 +1,10 @@ #pragma once -#include "fastfetch.h" +#include "common/ffdata.h" +#include "common/option.h" bool ffJsonConfigParseModuleArgs(yyjson_val* key, yyjson_val* val, FFModuleArgs* moduleArgs); const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair pairs[]); -void ffPrintJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc); -void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* moduleArgs); yyjson_api_inline yyjson_mut_val* yyjson_mut_strbuf(yyjson_mut_doc *doc, const FFstrbuf* buf) { return yyjson_mut_strncpy(doc, buf->chars, buf->length); @@ -23,3 +22,6 @@ yyjson_api_inline bool yyjson_mut_arr_add_strbuf(yyjson_mut_doc *doc, const FFstrbuf* buf) { return yyjson_mut_arr_add_strncpy(doc, obj, buf->chars, buf->length); } + +void ffPrintJsonConfig(FFdata* data, bool prepare); +void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* moduleArgs); diff --git a/src/fastfetch.c b/src/fastfetch.c index b57420473..d0882b15e 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -1,4 +1,5 @@ #include "fastfetch.h" +#include "common/ffdata.h" #include "detection/version/version.h" #include "logo/logo.h" #include "common/commandoption.h" @@ -379,16 +380,16 @@ static void listModules(bool pretty) } } -static bool parseJsoncFile(const char* path, yyjson_read_flag flg) +static bool parseJsoncFile(FFdata* data, const char* path, yyjson_read_flag flg) { - assert(!instance.state.configDoc); + assert(!data->configDoc); { yyjson_read_err error; - instance.state.configDoc = path + data->configDoc = path ? yyjson_read_file(path, flg, NULL, &error) : yyjson_read_fp(stdin, flg, NULL, &error); - if (!instance.state.configDoc) + if (!data->configDoc) { if (error.code != YYJSON_READ_ERROR_FILE_OPEN) { @@ -412,7 +413,7 @@ static bool parseJsoncFile(const char* path, yyjson_read_flag flg) { const char* error = NULL; - yyjson_val* const root = yyjson_doc_get_root(instance.state.configDoc); + yyjson_val* const root = yyjson_doc_get_root(data->configDoc); if (!yyjson_is_obj(root)) error = "Invalid JSON config format. Root value must be an object"; @@ -432,8 +433,14 @@ static bool parseJsoncFile(const char* path, yyjson_read_flag flg) } -static void generateConfigFile(bool force, const char* filePath, bool fullConfig) +static void generateConfigFile(FFdata* data, bool force, const char* filePath, bool fullConfig) { + if (data->resultDoc) + { + fprintf(stderr, "Error: duplicated `--gen-config` or `--format json` flags found\n"); + exit(477); + } + if (!filePath) { if (instance.state.platform.configDirs.length == 0) @@ -443,22 +450,23 @@ static void generateConfigFile(bool force, const char* filePath, bool fullConfig } FFstrbuf* configDir = FF_LIST_FIRST(FFstrbuf, instance.state.platform.configDirs); - ffStrbufEnsureFixedLengthFree(&instance.state.genConfigPath, configDir->length + strlen("fastfetch/config.jsonc")); - ffStrbufSet(&instance.state.genConfigPath, configDir); - ffStrbufAppendS(&instance.state.genConfigPath, "fastfetch/config.jsonc"); + ffStrbufEnsureFixedLengthFree(&data->genConfigPath, configDir->length + strlen("fastfetch/config.jsonc")); + ffStrbufSet(&data->genConfigPath, configDir); + ffStrbufAppendS(&data->genConfigPath, "fastfetch/config.jsonc"); } else { - ffStrbufSetS(&instance.state.genConfigPath, filePath); + ffStrbufSetS(&data->genConfigPath, filePath); } - if (!force && ffPathExists(instance.state.genConfigPath.chars, FF_PATHTYPE_ANY)) + if (!force && ffPathExists(data->genConfigPath.chars, FF_PATHTYPE_ANY)) { - fprintf(stderr, "Error: file `%s` exists. Use `--gen-config%s-force` to overwrite\n", instance.state.genConfigPath.chars, fullConfig ? "-full" : ""); + fprintf(stderr, "Error: file `%s` exists. Use `--gen-config%s-force` to overwrite\n", data->genConfigPath.chars, fullConfig ? "-full" : ""); exit(477); } - instance.state.fullConfig = fullConfig; + data->docType = fullConfig ? FF_RESULT_DOC_TYPE_CONFIG_FULL : FF_RESULT_DOC_TYPE_CONFIG; + data->resultDoc = yyjson_mut_doc_new(NULL); } static void optionParseConfigFile(FFdata* data, const char* key, const char* value) @@ -482,7 +490,7 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val if (value[0] == '-' && value[1] == '\0') { - parseJsoncFile(NULL, false); + parseJsoncFile(data, NULL, false); return; } @@ -503,7 +511,7 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val ? YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS : YYJSON_READ_JSON5; - if (parseJsoncFile(absolutePath.chars, flag)) return; + if (parseJsoncFile(data, absolutePath.chars, flag)) return; //Try to load as a relative path with the config directory @@ -515,7 +523,7 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val if (needExtension) ffStrbufAppendS(&absolutePath, ".jsonc"); - if (parseJsoncFile(absolutePath.chars, flag)) return; + if (parseJsoncFile(data, absolutePath.chars, flag)) return; } //Try to load as a preset @@ -528,7 +536,7 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val if (needExtension) ffStrbufAppendS(&absolutePath, ".jsonc"); - if (parseJsoncFile(absolutePath.chars, flag)) return; + if (parseJsoncFile(data, absolutePath.chars, flag)) return; } //Try to load as a relative path with the directory of fastfetch binary, for Windows support @@ -543,7 +551,7 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val ffStrbufAppendS(&absolutePath, value); if (needExtension) ffStrbufAppendS(&absolutePath, ".jsonc"); - if (parseJsoncFile(absolutePath.chars, flag)) return; + if (parseJsoncFile(data, absolutePath.chars, flag)) return; // Try {exePath}/presets/ ffStrbufSubstrBefore(&absolutePath, lastSlash); @@ -551,7 +559,7 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val ffStrbufAppendS(&absolutePath, value); if (needExtension) ffStrbufAppendS(&absolutePath, ".jsonc"); - if (parseJsoncFile(absolutePath.chars, flag)) return; + if (parseJsoncFile(data, absolutePath.chars, flag)) return; } //File not found @@ -566,24 +574,17 @@ static void printVersion() printf("%s %s%s%s (%s)\n", result->projectName, result->version, result->versionTweak, result->debugMode ? "-debug" : "", result->architecture); } -static void enableJsonOutput(bool enable) +static void enableJsonOutput(FFdata* data) { - if (!enable) + if (data->resultDoc) { - if (instance.state.resultDoc) - { - yyjson_mut_doc_free(instance.state.resultDoc); - instance.state.resultDoc = NULL; - } - } - else - { - if (!instance.state.resultDoc) - { - instance.state.resultDoc = yyjson_mut_doc_new(NULL); - yyjson_mut_doc_set_root(instance.state.resultDoc, yyjson_mut_arr(instance.state.resultDoc)); - } + fprintf(stderr, "Error: duplicated `--gen-config` or `--format json` flags found\n"); + exit(477); } + + data->resultDoc = yyjson_mut_doc_new(NULL); + data->docType = FF_RESULT_DOC_TYPE_JSON; + yyjson_mut_doc_set_root(data->resultDoc, yyjson_mut_arr(data->resultDoc)); } static void parseCommand(FFdata* data, char* key, char* value) @@ -668,24 +669,26 @@ static void parseCommand(FFdata* data, char* key, char* value) exit(0); } else if(ffStrEqualsIgnCase(key, "--gen-config")) - generateConfigFile(false, value, false); + generateConfigFile(data, false, value, false); else if(ffStrEqualsIgnCase(key, "--gen-config-force")) - generateConfigFile(true, value, false); + generateConfigFile(data, true, value, false); else if(ffStrEqualsIgnCase(key, "--gen-config-full")) - generateConfigFile(false, value, true); + generateConfigFile(data, false, value, true); else if(ffStrEqualsIgnCase(key, "--gen-config-full-force")) - generateConfigFile(true, value, true); + generateConfigFile(data, true, value, true); else if(ffStrEqualsIgnCase(key, "-c") || ffStrEqualsIgnCase(key, "--config")) optionParseConfigFile(data, key, value); else if(ffStrEqualsIgnCase(key, "-j") || ffStrEqualsIgnCase(key, "--json")) - enableJsonOutput(ffOptionParseBoolean(value)); + { + if (ffOptionParseBoolean(value)) enableJsonOutput(data); + } else if(ffStrEqualsIgnCase(key, "--format")) { - enableJsonOutput(!!ffOptionParseEnum(key, value, (FFKeyValuePair[]) { + if (!!ffOptionParseEnum(key, value, (FFKeyValuePair[]) { { "default", false}, { "json", true }, {}, - })); + })) enableJsonOutput(data); } else if(ffStrEqualsIgnCase(key, "--dynamic-interval")) instance.state.dynamicInterval = ffOptionParseUInt32(key, value); // seconds to milliseconds @@ -720,21 +723,21 @@ static void parseOption(FFdata* data, const char* key, const char* value) } } -static void parseConfigFiles(void) +static void parseConfigFiles(FFdata* data) { - if (__builtin_expect(instance.state.genConfigPath.length == 0, true)) + if (__builtin_expect(data->genConfigPath.length == 0, true)) { FF_LIST_FOR_EACH(FFstrbuf, dir, instance.state.platform.configDirs) { uint32_t dirLength = dir->length; ffStrbufAppendS(dir, "fastfetch/config.jsonc"); - bool success = parseJsoncFile(dir->chars, YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS); + bool success = parseJsoncFile(data, dir->chars, YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS); ffStrbufSubstrBefore(dir, dirLength); if (success) return; ffStrbufAppendS(dir, "fastfetch/config.json5"); - success = parseJsoncFile(dir->chars, YYJSON_READ_JSON5); + success = parseJsoncFile(data, dir->chars, YYJSON_READ_JSON5); ffStrbufSubstrBefore(dir, dirLength); if (success) return; } @@ -772,10 +775,10 @@ static void parseArguments(FFdata* data, int argc, char** argv, void (*parser)(F static void run(FFdata* data) { - const bool useJsonConfig = data->structure.length == 0 && instance.state.configDoc; + const bool useJsonConfig = data->structure.length == 0 && data->configDoc; if (useJsonConfig) - ffPrintJsonConfig(true /* prepare */, instance.state.resultDoc); + ffPrintJsonConfig(data, true /* prepare */); else { //If we don't have a custom structure, use the default one @@ -786,6 +789,9 @@ static void run(FFdata* data) ffStart(); + if (!data->resultDoc) + ffLogoPrint(); + #if defined(_WIN32) if (!instance.config.display.noBuffer) fflush(stdout); #endif @@ -793,9 +799,9 @@ static void run(FFdata* data) while (true) { if (useJsonConfig) - ffPrintJsonConfig(false, instance.state.resultDoc); + ffPrintJsonConfig(data, false); else - ffPrintCommandOption(data, instance.state.resultDoc); + ffPrintCommandOption(data); if (instance.state.dynamicInterval > 0) { @@ -807,8 +813,8 @@ static void run(FFdata* data) break; } - if (instance.state.resultDoc) - yyjson_mut_write_fp(stdout, instance.state.resultDoc, YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES | YYJSON_WRITE_NEWLINE_AT_END, NULL, NULL); + if (data->resultDoc) + yyjson_mut_write_fp(stdout, data->resultDoc, YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES | YYJSON_WRITE_NEWLINE_AT_END, NULL, NULL); else { if (instance.config.logo.printRemaining) @@ -819,20 +825,20 @@ static void run(FFdata* data) static void writeConfigFile(FFdata* data) { - const FFstrbuf* filename = &instance.state.genConfigPath; + const FFstrbuf* filename = &data->genConfigPath; - yyjson_mut_doc* doc = yyjson_mut_doc_new(NULL); + yyjson_mut_doc* doc = data->resultDoc; yyjson_mut_val* root = yyjson_mut_obj(doc); yyjson_mut_doc_set_root(doc, root); yyjson_mut_obj_add_str(doc, root, "$schema", "https://github.com/fastfetch-cli/fastfetch/raw/master/doc/json_schema.json"); - if (instance.state.fullConfig) + if (data->docType == FF_RESULT_DOC_TYPE_CONFIG_FULL) { - ffOptionsGenerateLogoJsonConfig(&instance.config.logo, doc); - ffOptionsGenerateDisplayJsonConfig(&instance.config.display, doc); - ffOptionsGenerateGeneralJsonConfig(&instance.config.general, doc); + ffOptionsGenerateLogoJsonConfig(data, &instance.config.logo); + ffOptionsGenerateDisplayJsonConfig(data, &instance.config.display); + ffOptionsGenerateGeneralJsonConfig(data, &instance.config.general); } - ffMigrateCommandOptionToJsonc(data, doc); + ffMigrateCommandOptionToJsonc(data); if (ffStrbufEqualS(filename, "-")) yyjson_mut_write_fp(stdout, doc, YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES | YYJSON_WRITE_NEWLINE_AT_END, NULL, NULL); @@ -857,8 +863,6 @@ static void writeConfigFile(FFdata* data) exit(1); } } - - yyjson_mut_doc_free(doc); } int main(int argc, char** argv) @@ -869,24 +873,29 @@ int main(int argc, char** argv) //Data stores things only needed for the configuration of fastfetch FFdata data = { .structure = ffStrbufCreate(), - .configLoaded = false, + .structureDisabled = ffStrbufCreate(), + .genConfigPath = ffStrbufCreate(), }; parseArguments(&data, argc, argv, parseCommand); - if(instance.state.dynamicInterval && instance.state.resultDoc) + if(instance.state.dynamicInterval && data.resultDoc) { fprintf(stderr, "Error: --dynamic-interval cannot be used with --json\n"); exit(400); } if(!data.configLoaded && !getenv("NO_CONFIG")) - parseConfigFiles(); + parseConfigFiles(&data); parseArguments(&data, argc, argv, (void*) parseOption); - if (__builtin_expect(instance.state.genConfigPath.length == 0, true)) + if (__builtin_expect(data.genConfigPath.length == 0, true)) run(&data); else writeConfigFile(&data); ffStrbufDestroy(&data.structure); + ffStrbufDestroy(&data.structureDisabled); + yyjson_doc_free(data.configDoc); + yyjson_mut_doc_free(data.resultDoc); + ffStrbufDestroy(&data.genConfigPath); } diff --git a/src/fastfetch.h b/src/fastfetch.h index 612799463..3b09b7e4d 100644 --- a/src/fastfetch.h +++ b/src/fastfetch.h @@ -5,12 +5,6 @@ #include #include -#ifdef FF_USE_SYSTEM_YYJSON - #include -#else - #include "3rdparty/yyjson/yyjson.h" -#endif - #ifdef _MSC_VER #define __attribute__(x) #endif @@ -40,13 +34,8 @@ typedef struct FFstate uint32_t keysHeight; bool terminalLightTheme; bool titleFqdn; - - FFPlatform platform; - yyjson_doc* configDoc; - yyjson_mut_doc* resultDoc; - FFstrbuf genConfigPath; - bool fullConfig; uint32_t dynamicInterval; + FFPlatform platform; } FFstate; typedef struct FFinstance diff --git a/src/flashfetch.c b/src/flashfetch.c index e4815686c..a185b6284 100644 --- a/src/flashfetch.c +++ b/src/flashfetch.c @@ -16,9 +16,12 @@ int main(void) instance.config.display.freqSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_NEVER; instance.config.display.sizeSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_NEVER; - // Logo printing and other preparation stuff + // Some preparation stuff ffStart(); + // Print logo + ffLogoPrint(); + // Print all modules { __attribute__((cleanup(ffDestroyTitleOptions))) FFTitleOptions options; diff --git a/src/logo/logo.c b/src/logo/logo.c index 1b09c6eea..2f009adc0 100644 --- a/src/logo/logo.c +++ b/src/logo/logo.c @@ -424,7 +424,8 @@ static void logoPrintStruct(const FFlogo* logo) static void logoPrintNone(void) { - logoApplyColors(logoGetBuiltinDetected(FF_LOGO_SIZE_NORMAL), false); + if (!instance.config.display.pipe) + logoApplyColors(logoGetBuiltinDetected(FF_LOGO_SIZE_NORMAL), false); instance.state.logoHeight = 0; instance.state.logoWidth = 0; } @@ -614,16 +615,6 @@ static bool logoTryKnownType(void) void ffLogoPrint(void) { - //When generate JSON result, we don't have a logo or padding. - //We also don't need to set main color, because it won't be printed anyway. - //So we can return quickly here. - if(instance.state.resultDoc) - { - instance.state.logoHeight = 0; - instance.state.logoWidth = 0; - return; - } - const FFOptionsLogo* options = &instance.config.logo; if (options->type == FF_LOGO_TYPE_NONE) diff --git a/src/options/display.c b/src/options/display.c index ef891a589..d828709b4 100644 --- a/src/options/display.c +++ b/src/options/display.c @@ -909,8 +909,9 @@ void ffOptionsDestroyDisplay(FFOptionsDisplay* options) ffListDestroy(&options->constants); } -void ffOptionsGenerateDisplayJsonConfig(FFOptionsDisplay* options, yyjson_mut_doc* doc) +void ffOptionsGenerateDisplayJsonConfig(FFdata* data, FFOptionsDisplay* options) { + yyjson_mut_doc* doc = data->resultDoc; yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, doc->root, "display"); if (options->stat <= 0) diff --git a/src/options/display.h b/src/options/display.h index 655ff1110..c9f798134 100644 --- a/src/options/display.h +++ b/src/options/display.h @@ -1,5 +1,6 @@ #pragma once +#include "common/ffdata.h" #include "common/percent.h" #include "common/FFstrbuf.h" #include "common/FFlist.h" @@ -98,4 +99,4 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va bool ffOptionsParseDisplayCommandLine(FFOptionsDisplay* options, const char* key, const char* value); void ffOptionsInitDisplay(FFOptionsDisplay* options); void ffOptionsDestroyDisplay(FFOptionsDisplay* options); -void ffOptionsGenerateDisplayJsonConfig(FFOptionsDisplay* options, yyjson_mut_doc* doc); +void ffOptionsGenerateDisplayJsonConfig(FFdata* data, FFOptionsDisplay* options); diff --git a/src/options/general.c b/src/options/general.c index c6daa4c13..77deb64fc 100644 --- a/src/options/general.c +++ b/src/options/general.c @@ -117,8 +117,9 @@ void ffOptionsDestroyGeneral(FF_MAYBE_UNUSED FFOptionsGeneral* options) #endif } -void ffOptionsGenerateGeneralJsonConfig(FFOptionsGeneral* options, yyjson_mut_doc* doc) +void ffOptionsGenerateGeneralJsonConfig(FFdata* data, FFOptionsGeneral* options) { + yyjson_mut_doc* doc = data->resultDoc; yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, doc->root, "general"); yyjson_mut_obj_add_bool(doc, obj, "thread", options->multithreading); diff --git a/src/options/general.h b/src/options/general.h index 5eda69e9c..22482011d 100644 --- a/src/options/general.h +++ b/src/options/general.h @@ -1,6 +1,6 @@ #pragma once -#include "common/FFstrbuf.h" +#include "common/ffdata.h" typedef enum __attribute__((__packed__)) FFDsForceDrmType { @@ -28,4 +28,4 @@ const char* ffOptionsParseGeneralJsonConfig(FFOptionsGeneral* options, yyjson_va bool ffOptionsParseGeneralCommandLine(FFOptionsGeneral* options, const char* key, const char* value); void ffOptionsInitGeneral(FFOptionsGeneral* options); void ffOptionsDestroyGeneral(FFOptionsGeneral* options); -void ffOptionsGenerateGeneralJsonConfig(FFOptionsGeneral* options, yyjson_mut_doc* doc); +void ffOptionsGenerateGeneralJsonConfig(FFdata* data, FFOptionsGeneral* options); diff --git a/src/options/logo.c b/src/options/logo.c index 1a5693f29..4542eae8e 100644 --- a/src/options/logo.c +++ b/src/options/logo.c @@ -466,8 +466,9 @@ const char* ffOptionsParseLogoJsonConfig(FFOptionsLogo* options, yyjson_val* roo return NULL; } -void ffOptionsGenerateLogoJsonConfig(FFOptionsLogo* options, yyjson_mut_doc* doc) +void ffOptionsGenerateLogoJsonConfig(FFdata* data, FFOptionsLogo* options) { + yyjson_mut_doc* doc = data->resultDoc; yyjson_mut_val* obj = yyjson_mut_obj(doc); switch (options->type) diff --git a/src/options/logo.h b/src/options/logo.h index 1d85663b3..dc2d84705 100644 --- a/src/options/logo.h +++ b/src/options/logo.h @@ -1,28 +1,28 @@ #pragma once -#include "common/FFstrbuf.h" +#include "common/ffdata.h" #define FASTFETCH_LOGO_MAX_NAMES 9 -#define FASTFETCH_LOGO_MAX_COLORS 9 //two digits would make parsing much more complicated (index 1 - 9) +#define FASTFETCH_LOGO_MAX_COLORS 9 // two digits would make parsing much more complicated (index 1 - 9) typedef enum __attribute__((__packed__)) 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_SMALL, //builtin ascii art, small version - 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_COMMAND_RAW, //command to generate 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_KITTY_DIRECT, //image file, tell the terminal emulator to read image data from the specified file (Supported by kitty and wezterm) - FF_LOGO_TYPE_IMAGE_KITTY_ICAT, //image file, use `kitten icat` to display the image. Requires binary `kitten` to be installed" - 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 + 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_SMALL, // builtin ascii art, small version + 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_COMMAND_RAW, // command to generate 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_KITTY_DIRECT, // image file, tell the terminal emulator to read image data from the specified file (Supported by kitty and wezterm) + FF_LOGO_TYPE_IMAGE_KITTY_ICAT, // image file, use `kitten icat` to display the image. Requires binary `kitten` to be installed" + 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`, but still applies colors to the system information output (unless `--pipe` is set) } FFLogoType; typedef enum __attribute__((__packed__)) FFLogoPosition @@ -58,4 +58,4 @@ void ffOptionsInitLogo(FFOptionsLogo* options); bool ffOptionsParseLogoCommandLine(FFOptionsLogo* options, const char* key, const char* value); void ffOptionsDestroyLogo(FFOptionsLogo* options); const char* ffOptionsParseLogoJsonConfig(FFOptionsLogo* options, yyjson_val* root); -void ffOptionsGenerateLogoJsonConfig(FFOptionsLogo* options, yyjson_mut_doc* doc); +void ffOptionsGenerateLogoJsonConfig(FFdata* data, FFOptionsLogo* options);