diff --git a/CHANGELOG.md b/CHANGELOG.md index e4db07808a..ab8888753a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,25 @@ +# 2.58.0 + +An early release to fix compatibility issues with KDE Plasma 6.6. + +Breaking changes: +* The `de.slowVersionDetection` option has been removed. Slow version detection is now always enabled, as required on non-FHS-compliant distros (e.g., NixOS). (#2149, DE, Linux) + +Features: +* Adds the `--structure-disabled ` command-line flag to temporarily disable module structure printing. + * For example: `fastfetch --structure-disabled colors` removes the color blocks from the default output. +* Supports chassis type detection on Linux ARM devices when reported via the device tree (Chassis, Linux) +* Supports Bedrock Linux version detection (#2155, OS, Linux) +* Honors the `DBPath` and `RootDir` settings in `pacman.conf` when detecting Pacman packages (#2154, Packages, Linux) + +Bugfixes: +* Fixes a crash issues on KDE Plasma 6.6 (Display, Linux) +* Fixes the Command module not working with `--dynamic-interval` (#2152, Command) +* Fixes Quartz Compositor version detection. It now correctly reports the version of `WindowServer` (`SkyLight`) instead of `WindowManager`. (WM, macOS) + +Logos: +* Adds Kiss2 + # 2.57.1 Features: diff --git a/CMakeLists.txt b/CMakeLists.txt index 05718e9705..07e197f02e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url project(fastfetch - VERSION 2.57.1 + VERSION 2.58.0 LANGUAGES C DESCRIPTION "Fast neofetch-like system information tool" HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch" diff --git a/LICENSE b/LICENSE index 3a3b50b1c0..e058633a65 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ MIT License Copyright (c) 2021-2023 Linus Dierheimer -Copyright (c) 2022-2025 Carter Li +Copyright (c) 2022-2026 Carter Li Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/debian/changelog.tpl b/debian/changelog.tpl index c6a75212b1..d89914a894 100644 --- a/debian/changelog.tpl +++ b/debian/changelog.tpl @@ -1,3 +1,9 @@ +fastfetch (2.57.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium + + * Update to 2.57.1 + + -- Carter Li Wed, 14 Jan 2026 14:00:17 +0800 + fastfetch (2.57.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium * Update to 2.57.0 diff --git a/doc/json_schema.json b/doc/json_schema.json index 92e8854713..37c2aba412 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -1999,7 +1999,7 @@ "additionalProperties": false, "properties": { "type": { - "description": "Print some colored blocks", + "description": "Display the terminal's 16-color palette", "const": "colors" }, "symbol": { diff --git a/presets/examples/10.jsonc b/presets/examples/10.jsonc index 5d43fe3262..4f342b10bf 100644 --- a/presets/examples/10.jsonc +++ b/presets/examples/10.jsonc @@ -1,4 +1,4 @@ -// Load with --load-config examples/2.jsonc +// Load with --config examples/2.jsonc // Note that you must replace the image path to an existing image to display it. { diff --git a/presets/examples/2.jsonc b/presets/examples/2.jsonc index 0ed382ad97..a7f5252b75 100644 --- a/presets/examples/2.jsonc +++ b/presets/examples/2.jsonc @@ -1,4 +1,4 @@ -// Load with --load-config examples/2.jsonc +// Load with --config examples/2.jsonc // Note that you must replace the image path to an existing image to display it. { diff --git a/presets/examples/3.jsonc b/presets/examples/3.jsonc index f3cb7d431b..4e9657e05a 100644 --- a/presets/examples/3.jsonc +++ b/presets/examples/3.jsonc @@ -1,4 +1,4 @@ -// Load with --load-config examples/3.jsonc +// Load with --config examples/3.jsonc { "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", diff --git a/presets/examples/4.jsonc b/presets/examples/4.jsonc index 9631644168..385af68b70 100644 --- a/presets/examples/4.jsonc +++ b/presets/examples/4.jsonc @@ -1,4 +1,4 @@ -// Load with --load-config examples/4.jsonc +// Load with --config examples/4.jsonc { "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", diff --git a/presets/examples/5.jsonc b/presets/examples/5.jsonc index 11b9c05e63..32f8e2e4d7 100644 --- a/presets/examples/5.jsonc +++ b/presets/examples/5.jsonc @@ -1,4 +1,4 @@ -// Load with --load-config examples/5.jsonc +// Load with --config examples/5.jsonc { "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", diff --git a/presets/examples/6.jsonc b/presets/examples/6.jsonc index 5eba94e5ae..c82b8af102 100644 --- a/presets/examples/6.jsonc +++ b/presets/examples/6.jsonc @@ -1,4 +1,4 @@ -// Load with --load-config examples/2.jsonc +// Load with --config examples/2.jsonc // Note that you must replace the image path to an existing image to display it. { diff --git a/presets/examples/7.jsonc b/presets/examples/7.jsonc index 7a3056e8bf..b17e5d39c0 100644 --- a/presets/examples/7.jsonc +++ b/presets/examples/7.jsonc @@ -1,4 +1,4 @@ -// Load with --load-config examples/2.jsonc +// Load with --config examples/2.jsonc // Note that you must replace the image path to an existing image to display it. { diff --git a/src/common/FFPlatform.h b/src/common/FFPlatform.h index bf3af78567..2962cbd171 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/FFstrbuf.h b/src/common/FFstrbuf.h index 7e82cdd4d0..59497b56eb 100644 --- a/src/common/FFstrbuf.h +++ b/src/common/FFstrbuf.h @@ -103,6 +103,10 @@ FF_C_NODISCARD uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultV void ffStrbufUpperCase(FFstrbuf* strbuf); void ffStrbufLowerCase(FFstrbuf* strbuf); +// Function alters the buffer to extract lines or delimited segments (replaces the delimiter with '\0') +// so that buffer MUST be heap allocated (NOT a static string) +// `lineptr` must be `NULL` and `n` MUST be `0` for the first call +// Caller MUST NOT free `*lineptr` bool ffStrbufGetdelim(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer); void ffStrbufGetdelimRestore(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer); @@ -111,10 +115,14 @@ void ffStrbufGetdelimRestore(char** lineptr, size_t* n, char delimiter, FFstrbuf * * @details Behaves like getline(3) but reads from a FFstrbuf. * - * @param[in,out] lineptr The pointer to a pointer that will be set to the start of the line. - * Can be NULL for the first call. + * @param[in,out] lineptr The pointer to a pointer that will be set to the start of the line + (points to buffer's internal memory address to avoid memory allocation and copy). + MUST NOT be freed by the caller, unlike `getline(3)`. + * MUST be NULL for the first call. * @param[in,out] n The pointer to the size of the buffer of lineptr. - * @param[in] buffer The buffer to read from. The buffer must not be a string literal. + MUST be 0 for the first call. + * @param[in] buffer The buffer to read from. + MUST be heap allocated (NOT a static string). * * @return true if a line has been read, false if the end of the buffer has been reached. */ @@ -124,7 +132,7 @@ static inline bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer) } /** * @brief Restore the end of a line that was modified by ffStrbufGetline. - * @warning This function should be called before breaking an ffStrbufGetline loop. + * @warning This function should be called before breaking an ffStrbufGetline loop if `buffer` will be used later. */ static inline void ffStrbufGetlineRestore(char** lineptr, size_t* n, FFstrbuf* buffer) { diff --git a/src/common/commandoption.h b/src/common/commandoption.h index 696bdb861f..5f64701b07 100644 --- a/src/common/commandoption.h +++ b/src/common/commandoption.h @@ -1,15 +1,8 @@ #pragma once -#include "fastfetch.h" - -// Things only needed by fastfetch -typedef struct FFdata -{ - FFstrbuf structure; - 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 0000000000..51b401ff3f --- /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 e19be4edcf..9b89a811ae 100644 --- a/src/common/impl/commandoption.c +++ b/src/common/impl/commandoption.c @@ -71,40 +71,66 @@ bool ffParseModuleOptions(const char* key, const char* value) void ffPrepareCommandOption(FFdata* data) { - if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_CPUUSAGE_MODULE_NAME, ':')) - ffPrepareCPUUsage(); - - if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_DISKIO_MODULE_NAME, ':')) + char* moduleType = NULL; + size_t moduleLen = 0; + while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure)) { - __attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options; - ffInitDiskIOOptions(&options); - ffPrepareDiskIO(&options); - } + #define FF_IF_MODULE_MATCH(moduleNameConstant) if (moduleLen == strlen(moduleNameConstant) \ + && ffStrEqualsIgnCase(moduleType, moduleNameConstant) \ + && !ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleNameConstant, ':')) - if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_NETIO_MODULE_NAME, ':')) - { - __attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options; - ffInitNetIOOptions(&options); - ffPrepareNetIO(&options); - } + switch (moduleType[0]) + { + case 'C': case 'c': + FF_IF_MODULE_MATCH(FF_CPUUSAGE_MODULE_NAME) + ffPrepareCPUUsage(); + break; - if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_PUBLICIP_MODULE_NAME, ':')) - { - __attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options; - ffInitPublicIpOptions(&options); - ffPreparePublicIp(&options); - } + case 'D': case 'd': + FF_IF_MODULE_MATCH(FF_DISKIO_MODULE_NAME) + { + __attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options; + ffInitDiskIOOptions(&options); + ffPrepareDiskIO(&options); + } + break; - if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_WEATHER_MODULE_NAME, ':')) - { - __attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options; - ffInitWeatherOptions(&options); - ffPrepareWeather(&options); + case 'N': case 'n': + FF_IF_MODULE_MATCH(FF_NETIO_MODULE_NAME) + { + __attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options; + ffInitNetIOOptions(&options); + ffPrepareNetIO(&options); + } + break; + + case 'P': case 'p': + FF_IF_MODULE_MATCH(FF_PUBLICIP_MODULE_NAME) + { + __attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options; + ffInitPublicIpOptions(&options); + ffPreparePublicIp(&options); + } + break; + + case 'W': case 'w': + FF_IF_MODULE_MATCH(FF_WEATHER_MODULE_NAME) + { + __attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options; + ffInitWeatherOptions(&options); + ffPrepareWeather(&options); + } + break; + } + + #undef FF_IF_MODULE_MATCH } } -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"); @@ -112,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); @@ -131,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) @@ -142,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])) @@ -156,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); @@ -169,30 +196,32 @@ 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; - uint32_t startIndex = 0; - while (startIndex < data->structure.length) + + char* moduleType = NULL; + size_t moduleLen = 0; + while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure)) { - uint32_t colonIndex = ffStrbufNextIndexC(&data->structure, startIndex, ':'); - data->structure.chars[colonIndex] = '\0'; + if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleType, ':')) + continue; double ms = 0; if(thres >= 0) ms = ffTimeGetTick(); - parseStructureCommand(data->structure.chars + startIndex, 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 { @@ -205,28 +234,24 @@ void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc) } #if defined(_WIN32) - if (!jsonDoc && !instance.config.display.noBuffer) fflush(stdout); + if (!data->resultDoc && !instance.config.display.noBuffer) fflush(stdout); #endif - - startIndex = colonIndex + 1; } } -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) ffStrbufAppendS(&data->structure, FASTFETCH_DATATEXT_STRUCTURE); // Cannot use `ffStrbufSetStatic` here because we will modify the string - //Parse the structure and call the modules - uint32_t startIndex = 0; - while (startIndex < data->structure.length) + char* moduleType = NULL; + size_t moduleLen = 0; + while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure)) { - uint32_t colonIndex = ffStrbufNextIndexC(&data->structure, startIndex, ':'); - data->structure.chars[colonIndex] = '\0'; - - parseStructureCommand(data->structure.chars + startIndex, genJsonConfig, jsonDoc); + if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleType, ':')) + continue; - startIndex = colonIndex + 1; + parseStructureCommand(data, moduleType, genJsonConfig); } } diff --git a/src/common/impl/init.c b/src/common/impl/init.c index ae28316d60..ab9d0ad53c 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 f1e270b483..5e5effb08e 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)) @@ -298,6 +299,9 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc) else return "modules must be an array of strings or objects"; + if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, type, ':')) + continue; + if(prepare) prepareModuleJsonObject(type, module); else @@ -329,9 +333,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 08a297f752..55f9ab5f89 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/data/help.json b/src/data/help.json index b784ec6500..0be2b8c8e3 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -468,6 +468,14 @@ "default": "\"fastfetch --print-structure\"" } }, + { + "long": "structure-disabled", + "desc": "Disable specific modules in the structure", + "remark": "Must be a colon-separated list of keys", + "arg": { + "type": "structure" + } + }, { "long": "stat", "desc": "Show time usage (in ms) for individual modules", diff --git a/src/detection/board/board_linux.c b/src/detection/board/board_linux.c index 1a10ea3eb4..e9ebb3d18c 100644 --- a/src/detection/board/board_linux.c +++ b/src/detection/board/board_linux.c @@ -2,8 +2,6 @@ #include "common/io.h" #include "common/smbiosHelper.h" -#include - const char* ffDetectBoard(FFBoardResult* board) { if (ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_name", "/sys/class/dmi/id/board_name", &board->name)) @@ -12,11 +10,17 @@ const char* ffDetectBoard(FFBoardResult* board) ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_vendor", "/sys/class/dmi/id/board_vendor", &board->vendor); ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_version", "/sys/class/dmi/id/board_version", &board->version); } - else if (ffReadFileBuffer("/proc/device-tree/board", &board->name)) + else if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/baseboard/product", &board->name)) + { + ffStrbufTrimRight(&board->name, '\0'); + if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/baseboard/manufacturer", &board->vendor)) + ffStrbufTrimRight(&board->vendor, '\0'); + } + else if (ffReadFileBuffer("/sys/firmware/devicetree/base/board", &board->name)) { ffStrbufTrimRightSpace(&board->name); } - else if (ffReadFileBuffer("/proc/device-tree/compatible", &board->vendor)) + else if (ffReadFileBuffer("/sys/firmware/devicetree/base/compatible", &board->vendor)) { uint32_t comma = ffStrbufFirstIndexC(&board->vendor, ','); if (comma < board->vendor.length) diff --git a/src/detection/chassis/chassis_linux.c b/src/detection/chassis/chassis_linux.c index d44d9bddf1..999f0036a5 100644 --- a/src/detection/chassis/chassis_linux.c +++ b/src/detection/chassis/chassis_linux.c @@ -2,20 +2,42 @@ #include "common/io.h" #include "common/smbiosHelper.h" -#include +#include const char* ffDetectChassis(FFChassisResult* result) { - ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_type", "/sys/class/dmi/id/chassis_type", &result->type); - ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_serial", "/sys/class/dmi/id/chassis_serial", &result->serial); - ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_vendor", "/sys/class/dmi/id/chassis_vendor", &result->vendor); - ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_version", "/sys/class/dmi/id/chassis_version", &result->version); + if (ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_type", "/sys/class/dmi/id/chassis_type", &result->type)) + { + ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_serial", "/sys/class/dmi/id/chassis_serial", &result->serial); + ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_vendor", "/sys/class/dmi/id/chassis_vendor", &result->vendor); + ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_version", "/sys/class/dmi/id/chassis_version", &result->version); - if(result->type.length) + if(result->type.length) + { + const char* typeStr = ffChassisTypeToString((uint32_t) ffStrbufToUInt(&result->type, 9999)); + if(typeStr) + ffStrbufSetStatic(&result->type, typeStr); + } + } + else { - const char* typeStr = ffChassisTypeToString((uint32_t) ffStrbufToUInt(&result->type, 9999)); - if(typeStr) - ffStrbufSetS(&result->type, typeStr); + // Available on Asahi Linux + uint32_t chassisType = 0; + if (ffReadFileData("/sys/firmware/devicetree/base/smbios/smbios/chassis/chassis-type", sizeof(chassisType), &chassisType)) // big endian + { + chassisType = __builtin_bswap32(chassisType); + const char* typeStr = ffChassisTypeToString(chassisType); + if(typeStr) + ffStrbufSetStatic(&result->type, typeStr); + + if(ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/chassis/manufacturer", &result->vendor) && result->vendor.length > 0) + ffStrbufTrimRight(&result->vendor, '\0'); + } + else if(ffReadFileBuffer("/sys/firmware/devicetree/base/chassis-type", &result->type) && result->type.length > 0) + { + ffStrbufTrimRight(&result->type, '\0'); + result->type.chars[0] = (char) toupper(result->type.chars[0]); + } } return NULL; } diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c index b6cb7b0543..cdbf58413a 100644 --- a/src/detection/cpu/cpu_linux.c +++ b/src/detection/cpu/cpu_linux.c @@ -741,7 +741,7 @@ FF_MAYBE_UNUSED static void detectSocName(FFCPUResult* cpu) // [x-vendor,x-model\0]*N char content[512]; - ssize_t length = ffReadFileData("/proc/device-tree/compatible", ARRAY_SIZE(content), content); + ssize_t length = ffReadFileData("/sys/firmware/devicetree/base/compatible", ARRAY_SIZE(content), content); if (length < 4) return; // v,m\0 if (content[length - 1] != '\0') return; // must end with \0 diff --git a/src/detection/cpuusage/cpuusage.c b/src/detection/cpuusage/cpuusage.c index 40e569528b..72393aa45c 100644 --- a/src/detection/cpuusage/cpuusage.c +++ b/src/detection/cpuusage/cpuusage.c @@ -9,7 +9,8 @@ static uint64_t startTime; void ffPrepareCPUUsage(void) { - assert(cpuTimes1.elementSize == 0); + if (cpuTimes1.elementSize != 0) return; // Already prepared + ffListInit(&cpuTimes1, sizeof(FFCpuUsageInfo)); ffGetCpuUsageInfo(&cpuTimes1); startTime = ffTimeGetNow(); diff --git a/src/detection/de/de_linux.c b/src/detection/de/de_linux.c index b4d4e4eb95..ee2aeafcc5 100644 --- a/src/detection/de/de_linux.c +++ b/src/detection/de/de_linux.c @@ -22,7 +22,7 @@ #define _PATH_LOCALBASE "/usr/pkg" #endif -static void getKDE(FFstrbuf* result, FFDEOptions* options) +static void getKDE(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options) { #ifdef _PATH_LOCALBASE ffParsePropFile(_PATH_LOCALBASE "/share/wayland-sessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result); @@ -44,7 +44,7 @@ static void getKDE(FFstrbuf* result, FFDEOptions* options) if(result->length == 0) ffParsePropFileData("wayland-sessions/plasmawayland5.desktop", "X-KDE-PluginInfo-Version =", result); - if(result->length == 0 && options->slowVersionDetection) + if(result->length == 0) { if (ffProcessAppendStdOut(result, (char* const[]){ "plasmashell", @@ -73,7 +73,7 @@ static void getGnome(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options) { getGnomeByDbus(result); - if (result->length == 0 && options->slowVersionDetection) + if (result->length == 0) { if (ffProcessAppendStdOut(result, (char* const[]){ "gnome-shell", @@ -91,7 +91,7 @@ static void getCinnamon(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options) if (result->length == 0) ffParsePropFileData("applications/cinnamon.desktop", "X-GNOME-Bugzilla-Version =", result); - if (result->length == 0 && options->slowVersionDetection) + if (result->length == 0) { if (ffProcessAppendStdOut(result, (char* const[]){ "cinnamon", @@ -102,7 +102,7 @@ static void getCinnamon(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options) } } -static void getMate(FFstrbuf* result, FFDEOptions* options) +static void getMate(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options) { FF_STRBUF_AUTO_DESTROY major = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY minor = ffStrbufCreate(); @@ -116,7 +116,7 @@ static void getMate(FFstrbuf* result, FFDEOptions* options) ffParseSemver(result, &major, &minor, µ); - if(result->length == 0 && options->slowVersionDetection) + if(result->length == 0) { ffProcessAppendStdOut(result, (char* const[]){ "mate-session", @@ -143,11 +143,11 @@ static const char* getXfce4ByLib(FFstrbuf* result) #endif } -static void getXFCE4(FFstrbuf* result, FFDEOptions* options) +static void getXFCE4(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options) { getXfce4ByLib(result); - if(result->length == 0 && options->slowVersionDetection) + if(result->length == 0) { //This is somewhat slow ffProcessAppendStdOut(result, (char* const[]){ @@ -162,7 +162,7 @@ static void getXFCE4(FFstrbuf* result, FFDEOptions* options) } } -static void getLXQt(FFstrbuf* result, FFDEOptions* options) +static void getLXQt(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options) { ffParsePropFileData("gconfig/lxqt.pc", "Version:", result); @@ -171,7 +171,7 @@ static void getLXQt(FFstrbuf* result, FFDEOptions* options) if(result->length == 0) ffParsePropFileData("cmake/lxqt/lxqt-config-version.cmake", "set ( PACKAGE_VERSION", result); - if(result->length == 0 && options->slowVersionDetection) + if(result->length == 0) { //This is really, really, really slow. Thank you, LXQt developers ffProcessAppendStdOut(result, (char* const[]){ @@ -206,7 +206,7 @@ static bool extractTdeVersion(const char* line, uint32_t len, void *userdata) return false; } -static const char* getTrinity(FFstrbuf* result, FFDEOptions* options) +static const char* getTrinity(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options) { FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate(); const char* error = ffFindExecutableInPath("tde-config", &path); @@ -218,15 +218,13 @@ static const char* getTrinity(FFstrbuf* result, FFDEOptions* options) if (ffBinaryExtractStrings(path.chars, extractTdeVersion, result, strlen("R0.0.0")) == NULL) return NULL; - if (options->slowVersionDetection) + ffStrbufClear(&path); + if (ffProcessAppendStdOut(&path, (char* const[]){ + "tde-config", + "--version", + NULL + }) == NULL) { - ffStrbufClear(&path); - ffProcessAppendStdOut(&path, (char* const[]){ - "tde-config", - "--version", - NULL - }); - ffParsePropLines(path.chars , "TDE: ", result); return NULL; } diff --git a/src/detection/diskio/diskio.c b/src/detection/diskio/diskio.c index 9413a7125e..00f7bc2448 100644 --- a/src/detection/diskio/diskio.c +++ b/src/detection/diskio/diskio.c @@ -11,6 +11,8 @@ void ffPrepareDiskIO(FFDiskIOOptions* options) { if (options->detectTotal) return; + if (time1 != 0) return; // Already prepared + ffListInit(&ioCounters1, sizeof(FFDiskIOResult)); ffDiskIOGetIoCounters(&ioCounters1, options); time1 = ffTimeGetNow(); diff --git a/src/detection/displayserver/linux/wayland/kde-output.c b/src/detection/displayserver/linux/wayland/kde-output.c index afdfcf1931..d9514dd072 100644 --- a/src/detection/displayserver/linux/wayland/kde-output.c +++ b/src/detection/displayserver/linux/wayland/kde-output.c @@ -39,6 +39,7 @@ static const struct kde_output_device_mode_v2_listener modeListener = { .refresh = waylandKdeModeRefreshListener, .preferred = waylandKdeModePreferredListener, .removed = (void*) stubListener, + .flags = (void*) stubListener, }; static void waylandKdeModeListener(void* data, FF_MAYBE_UNUSED struct kde_output_device_v2* _, struct kde_output_device_mode_v2 *mode) diff --git a/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-client-protocol.h b/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-client-protocol.h index dfade7510e..2f848e6a6f 100644 --- a/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-client-protocol.h +++ b/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-client-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.22.0 */ +/* Generated by wayland-scanner 1.24.0 */ #ifndef WLR_OUTPUT_MANAGEMENT_UNSTABLE_V1_CLIENT_PROTOCOL_H #define WLR_OUTPUT_MANAGEMENT_UNSTABLE_V1_CLIENT_PROTOCOL_H @@ -445,9 +445,8 @@ struct zwlr_output_head_v1_listener { * However, do not assume that the name is a reflection of an * underlying DRM connector, X11 connection, etc. * - * If the compositor implements the xdg-output protocol and this - * head is enabled, the xdg_output.name event must report the same - * name. + * If this head matches a wl_output, the wl_output.name event must + * report the same name. * * The name event is sent after a wlr_output_head object is * created. This event is only sent once per object, and the name @@ -468,9 +467,8 @@ struct zwlr_output_head_v1_listener { * underlying DRM connector or the display name of the underlying * X11 connection, etc. * - * If the compositor implements xdg-output and this head is - * enabled, the xdg_output.description must report the same - * description. + * If this head matches a wl_output, the wl_output.description + * event must report the same name. * * The description event is sent after a wlr_output_head object is * created. This event is only sent once per object, and the @@ -486,6 +484,11 @@ struct zwlr_output_head_v1_listener { * This event describes the physical size of the head. This event * is only sent if the head has a physical size (e.g. is not a * projector or a virtual device). + * + * The physical size event is sent after a wlr_output_head object + * is created. This event is only sent once per object, and the + * physical size does not change over the lifetime of the + * wlr_output_head object. * @param width width in millimeters of the output * @param height height in millimeters of the output */ @@ -568,9 +571,6 @@ struct zwlr_output_head_v1_listener { * * This event describes the manufacturer of the head. * - * This must report the same make as the wl_output interface does - * in its geometry event. - * * Together with the model and serial_number events the purpose is * to allow clients to recognize heads from previous sessions and * for example load head-specific configurations back. @@ -583,6 +583,10 @@ struct zwlr_output_head_v1_listener { * other events but should be aware that there is an increased risk * of false positives. * + * If sent, the make event is sent after a wlr_output_head object + * is created and only sent once per object. The make does not + * change over the lifetime of the wlr_output_head object. + * * It is not recommended to display the make string in UI to users. * For that the string provided by the description event should be * preferred. @@ -596,9 +600,6 @@ struct zwlr_output_head_v1_listener { * * This event describes the model of the head. * - * This must report the same model as the wl_output interface does - * in its geometry event. - * * Together with the make and serial_number events the purpose is * to allow clients to recognize heads from previous sessions and * for example load head-specific configurations back. @@ -611,6 +612,10 @@ struct zwlr_output_head_v1_listener { * information from other events but should be aware that there is * an increased risk of false positives. * + * If sent, the model event is sent after a wlr_output_head object + * is created and only sent once per object. The model does not + * change over the lifetime of the wlr_output_head object. + * * It is not recommended to display the model string in UI to * users. For that the string provided by the description event * should be preferred. @@ -636,6 +641,11 @@ struct zwlr_output_head_v1_listener { * events but should be aware that there is an increased risk of * false positives. * + * If sent, the serial number event is sent after a wlr_output_head + * object is created and only sent once per object. The serial + * number does not change over the lifetime of the wlr_output_head + * object. + * * It is not recommended to display the serial_number string in UI * to users. For that the string provided by the description event * should be preferred. diff --git a/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c b/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c index aaa2663e6f..5eb1174ac5 100644 --- a/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c +++ b/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c @@ -1,6 +1,6 @@ #ifdef FF_HAVE_WAYLAND -/* Generated by wayland-scanner 1.22.0 */ +/* Generated by wayland-scanner 1.24.0 */ /* * Copyright © 2019 Purism SPC @@ -27,6 +27,7 @@ * THIS SOFTWARE. */ +#include #include #include #include diff --git a/src/detection/gpu/gpu_windows.c b/src/detection/gpu/gpu_windows.c index 85ce19f1d6..853cb5217f 100644 --- a/src/detection/gpu/gpu_windows.c +++ b/src/detection/gpu/gpu_windows.c @@ -54,6 +54,12 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* } FF_DEBUG("Device instance ID: %lu", devInst); + for (wchar_t* p = devId; *p; p++) + { + if (*p >= L'a' && *p <= L'z') + *p -= L'a' - L'A'; + } + FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus); deviceCount++; FF_DEBUG("Added GPU #%d to list", deviceCount); @@ -73,10 +79,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpu->frequency = FF_GPU_FREQUENCY_UNSET; unsigned vendorId = 0, deviceId = 0, subSystemId = 0, revId = 0; - if ( - (*devId == 'P' && swscanf(devId, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId) == 4) || - (*devId == 'p' && swscanf(devId, L"pci\\ven_%x&dev_%x&subsys_%x&rev_%x", &vendorId, &deviceId, &subSystemId, &revId) == 4) // Windows 7 - ) + if (swscanf(devId, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId) == 4) { FF_DEBUG("Parsed PCI IDs - Vendor: 0x%x, Device: 0x%x, SubSystem: 0x%x, Rev: 0x%x", vendorId, deviceId, subSystemId, revId); ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId)); diff --git a/src/detection/host/host_linux.c b/src/detection/host/host_linux.c index 1ce20ccee7..b6f3fa745d 100644 --- a/src/detection/host/host_linux.c +++ b/src/detection/host/host_linux.c @@ -9,18 +9,14 @@ static void getHostProductName(FFstrbuf* name) { if (ffReadFileBuffer("/sys/firmware/devicetree/base/model", name)) { - ffStrbufTrimRightSpace(name); ffStrbufTrimRight(name, '\0'); - if(ffIsSmbiosValueSet(name)) - return; + return; } if (ffReadFileBuffer("/sys/firmware/devicetree/base/banner-name", name)) { - ffStrbufTrimRightSpace(name); ffStrbufTrimRight(name, '\0'); - if(ffIsSmbiosValueSet(name)) - return; + return; } if (ffReadFileBuffer("/tmp/sysinfo/model", name)) @@ -36,20 +32,19 @@ static void getHostProductName(FFstrbuf* name) static void getHostSerialNumber(FFstrbuf* serial) { - if (ffReadFileBuffer("/sys/firmware/devicetree/base/serial-number", serial)) - { - ffStrbufTrimRightSpace(serial); + if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/system/serial", serial)) + ffStrbufTrimRight(serial, '\0'); + else if (ffReadFileBuffer("/sys/firmware/devicetree/base/serial-number", serial)) ffStrbufTrimRight(serial, '\0'); - if(ffIsSmbiosValueSet(serial)) - return; - } - - ffStrbufClear(serial); } const char* ffDetectHost(FFHostResult* host) { - ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->family); + if (!ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->family)) + { + if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/system/product", &host->family)) + ffStrbufTrimRight(&host->family, '\0'); + } if (!ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_name", "/sys/class/dmi/id/product_name", &host->name)) getHostProductName(&host->name); ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_version", "/sys/class/dmi/id/product_version", &host->version); @@ -59,8 +54,8 @@ const char* ffDetectHost(FFHostResult* host) ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_uuid", "/sys/class/dmi/id/product_uuid", &host->uuid); if (!ffGetSmbiosValue("/sys/devices/virtual/dmi/id/sys_vendor", "/sys/class/dmi/id/sys_vendor", &host->vendor)) { - if (ffStrbufStartsWithS(&host->name, "Apple ")) - ffStrbufSetStatic(&host->vendor, "Apple Inc."); + if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/system/manufacturer", &host->vendor)) + ffStrbufTrimRight(&host->vendor, '\0'); } #ifdef __x86_64__ diff --git a/src/detection/netio/netio.c b/src/detection/netio/netio.c index 666321c996..48d6ba7b15 100644 --- a/src/detection/netio/netio.c +++ b/src/detection/netio/netio.c @@ -9,6 +9,8 @@ void ffPrepareNetIO(FFNetIOOptions* options) { if (options->detectTotal) return; + if (time1 != 0) return; // Already prepared + ffListInit(&ioCounters1, sizeof(FFNetIOResult)); ffNetIOGetIoCounters(&ioCounters1, options); time1 = ffTimeGetNow(); diff --git a/src/detection/os/os_linux.c b/src/detection/os/os_linux.c index 3377ec2a10..14c06a7750 100644 --- a/src/detection/os/os_linux.c +++ b/src/detection/os/os_linux.c @@ -313,21 +313,7 @@ static bool detectBedrock(FFOSResult* os) { const char* bedrockRestrict = getenv("BEDROCK_RESTRICT"); if(bedrockRestrict && bedrockRestrict[0] == '1') return false; - if(parseOsRelease(FASTFETCH_TARGET_DIR_ROOT "/bedrock" FASTFETCH_TARGET_DIR_ETC "/bedrock-release", os)) - { - if(os->id.length == 0) - ffStrbufAppendS(&os->id, "bedrock"); - - if(os->name.length == 0) - ffStrbufAppendS(&os->name, "Bedrock"); - - if(os->prettyName.length == 0) - ffStrbufAppendS(&os->prettyName, "Bedrock Linux"); - - parseOsRelease("/bedrock" FASTFETCH_TARGET_DIR_ETC "/os-release", os); - return true; - } - return false; + return parseOsRelease(FASTFETCH_TARGET_DIR_ROOT "/bedrock/strata/bedrock/etc/os-release", os); } static void detectOS(FFOSResult* os) diff --git a/src/detection/packages/packages_linux.c b/src/detection/packages/packages_linux.c index e2f4a6b232..07998bc91a 100644 --- a/src/detection/packages/packages_linux.c +++ b/src/detection/packages/packages_linux.c @@ -412,6 +412,45 @@ static uint32_t getFlatpakPackages(FFstrbuf* baseDir, const char* dirname) return num_elements; } +static uint32_t getPacmanPackages(FFstrbuf* baseDir) +{ + FF_STRBUF_AUTO_DESTROY dbPath = ffStrbufCreate(); + FF_STRBUF_AUTO_DESTROY rootDir = ffStrbufCreate(); + + // Get path to pacman.conf + uint32_t baseDirLen = baseDir->length; + ffStrbufAppendS(baseDir, "/etc/pacman.conf"); + + bool confFound = ffParsePropFileValues(baseDir->chars, 2, (FFpropquery[]){ + { "DBPath =", &dbPath }, + { "RootDir =", &rootDir }, + }); + ffStrbufSubstrBefore(baseDir, baseDirLen); + + if (confFound) + { + if (dbPath.length > 0) + { + // If DBPath is specified, use it + ffStrbufEnsureEndsWithC(&dbPath, '/'); + ffStrbufAppendS(&dbPath, "local"); + } + else if (rootDir.length > 0) + { + // ... otherwise, use RootDir + ffStrbufDestroy(&dbPath); + ffStrbufInitMove(&dbPath, &rootDir); + ffStrbufEnsureEndsWithC(&dbPath, '/'); + ffStrbufAppendS(&dbPath, "var/lib/pacman/local"); + } + } + + if (dbPath.length == 0) + ffStrbufSetStatic(&dbPath, "/var/lib/pacman/local"); + + return getNumElements(baseDir, dbPath.chars, true); +} + static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts, FFPackagesOptions* options) { if (!(options->disabled & FF_PACKAGES_FLAG_APK_BIT)) packageCounts->apk += getNumStrings(baseDir, "/lib/apk/db/installed", "C:Q", "apk"); @@ -426,7 +465,7 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts, packageCounts->nixDefault += ffPackagesGetNix(baseDir, "/nix/var/nix/profiles/default"); packageCounts->nixSystem += ffPackagesGetNix(baseDir, "/run/current-system"); } - if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) packageCounts->pacman += getNumElements(baseDir, "/var/lib/pacman/local", true); + if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) packageCounts->pacman += getPacmanPackages(baseDir); if (!(options->disabled & FF_PACKAGES_FLAG_LPKGBUILD_BIT)) packageCounts->lpkgbuild += getNumElements(baseDir, "/opt/Loc-OS-LPKG/lpkgbuild/remove", false); if (!(options->disabled & FF_PACKAGES_FLAG_PKGTOOL_BIT)) packageCounts->pkgtool += getNumElements(baseDir, "/var/log/packages", false); if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT)) diff --git a/src/detection/wm/wm_apple.m b/src/detection/wm/wm_apple.m index 6f595e4671..2036cfd12c 100644 --- a/src/detection/wm/wm_apple.m +++ b/src/detection/wm/wm_apple.m @@ -50,9 +50,16 @@ if (ffStrbufEqualS(wmName, "WindowServer")) { NSError* error; - NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:@"file:///System/Library/CoreServices/WindowManager.app/Contents/version.plist"] + NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:@"file:///System/Library/PrivateFrameworks/SkyLight.framework/Resources/version.plist"] error:&error]; - ffStrbufInitS(result, ((NSString*) dict[@"CFBundleVersion"]).UTF8String); + if (!dict) + { + dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:@"file:///System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Resources/version.plist"] + error:&error]; + } + + if (dict) + ffStrbufInitS(result, ((NSString*) dict[@"CFBundleShortVersionString"]).UTF8String); } return NULL; diff --git a/src/fastfetch.c b/src/fastfetch.c index 840790bef8..60df8051f4 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 (instance.state.resultDoc) - { - yyjson_mut_doc_free(instance.state.resultDoc); - instance.state.resultDoc = NULL; - } - } - else + if (data->resultDoc) { - 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 @@ -710,6 +713,9 @@ static void parseOption(FFdata* data, const char* key, const char* value) ffParseModuleOptions(key, value) ) {} + else if(ffStrEqualsIgnCase(key, "--structure-disabled")) + ffOptionParseString(key, value, &data->structureDisabled); + else { fprintf(stderr, "Error: unknown option: %s\n", key); @@ -717,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; } @@ -769,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 @@ -783,6 +789,9 @@ static void run(FFdata* data) ffStart(); + if (!data->resultDoc) + ffLogoPrint(); + #if defined(_WIN32) if (!instance.config.display.noBuffer) fflush(stdout); #endif @@ -790,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) { @@ -802,10 +811,15 @@ static void run(FFdata* data) } else break; + + if (useJsonConfig) + ffPrintJsonConfig(data, true /* prepare */); + else + ffPrepareCommandOption(data); } - 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) @@ -816,20 +830,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); @@ -854,8 +868,6 @@ static void writeConfigFile(FFdata* data) exit(1); } } - - yyjson_mut_doc_free(doc); } int main(int argc, char** argv) @@ -866,24 +878,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 6127994634..3b09b7e4d0 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 e4815686c4..a185b62845 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/ascii/kiss2.txt b/src/logo/ascii/kiss2.txt new file mode 100644 index 0000000000..1fbd6ae92a --- /dev/null +++ b/src/logo/ascii/kiss2.txt @@ -0,0 +1,11 @@ + ██████ ██████ + ██$2██████$1████$2██████$1██ + ██$3████$2████████████████$1██ + ██$2██$3████$2██████████████████$1██ +██$2██$3██$2████$3████████████$2████████$1██ +██$2██████$3████████████████$2██████$1██ +██$2████████████████████████████$1██ + ██$2████████████████████████$1██ + ██$2██████$3████████$2██████$1██ + ████$2████████████$1████ + ████████████ \ No newline at end of file diff --git a/src/logo/builtin.c b/src/logo/builtin.c index 996fb79e93..7b4b366341 100644 --- a/src/logo/builtin.c +++ b/src/logo/builtin.c @@ -2536,6 +2536,18 @@ static const FFlogo K[] = { .colorKeys = FF_COLOR_FG_MAGENTA, .colorTitle = FF_COLOR_FG_BLUE, }, + // KISSLinux2 + { + .names = {"kiss2"}, + .lines = FASTFETCH_DATATEXT_LOGO_KISS2, + .colors = { + FF_COLOR_FG_BLACK, + FF_COLOR_FG_RED, + FF_COLOR_FG_WHITE, + }, + .colorKeys = FF_COLOR_FG_RED, + .colorTitle = FF_COLOR_FG_RED, + }, // Kogaion { .names = {"Kogaion"}, diff --git a/src/logo/logo.c b/src/logo/logo.c index 1b09c6eead..1bd6cb8e94 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) @@ -711,7 +702,7 @@ void ffLogoPrintLine(void) printf("\033[%uC", instance.state.logoWidth); if (instance.state.dynamicInterval > 0) - fputs("\033[K", stdout); + fputs("\033[K", stdout); // Clear to the end of the line ++instance.state.keysHeight; } diff --git a/src/modules/colors/colors.c b/src/modules/colors/colors.c index e831920e94..fb5aed0f6b 100644 --- a/src/modules/colors/colors.c +++ b/src/modules/colors/colors.c @@ -249,7 +249,7 @@ void ffDestroyColorsOptions(FFColorsOptions* options) FFModuleBaseInfo ffColorsModuleInfo = { .name = FF_COLORS_MODULE_NAME, - .description = "Print some colored blocks", + .description = "Display the terminal's 16-color palette", .initOptions = (void*) ffInitColorsOptions, .destroyOptions = (void*) ffDestroyColorsOptions, .parseJsonObject = (void*) ffParseColorsJsonObject, diff --git a/src/modules/de/de.c b/src/modules/de/de.c index 04f9544648..758d20ef28 100644 --- a/src/modules/de/de.c +++ b/src/modules/de/de.c @@ -55,7 +55,7 @@ void ffParseDEJsonObject(FFDEOptions* options, yyjson_val* module) if (unsafe_yyjson_equals_str(key, "slowVersionDetection")) { - options->slowVersionDetection = yyjson_get_bool(val); + ffPrintError(FF_DE_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Key `slowVersionDetection` is deprecated, it's always true"); continue; } @@ -66,8 +66,6 @@ void ffParseDEJsonObject(FFDEOptions* options, yyjson_val* module) void ffGenerateDEJsonConfig(FFDEOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) { ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs); - - yyjson_mut_obj_add_bool(doc, module, "slowVersionDetection", options->slowVersionDetection); } bool ffGenerateDEJsonResult(FF_MAYBE_UNUSED FFDEOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) @@ -93,8 +91,6 @@ bool ffGenerateDEJsonResult(FF_MAYBE_UNUSED FFDEOptions* options, yyjson_mut_doc void ffInitDEOptions(FFDEOptions* options) { ffOptionInitModuleArg(&options->moduleArgs, ""); - - options->slowVersionDetection = false; } void ffDestroyDEOptions(FFDEOptions* options) diff --git a/src/modules/de/option.h b/src/modules/de/option.h index c587a0c96b..1c0188b8c8 100644 --- a/src/modules/de/option.h +++ b/src/modules/de/option.h @@ -5,8 +5,6 @@ typedef struct FFDEOptions { FFModuleArgs moduleArgs; - - bool slowVersionDetection; } FFDEOptions; static_assert(sizeof(FFDEOptions) <= FF_OPTION_MAX_SIZE, "FFDEOptions size exceeds maximum allowed size"); diff --git a/src/options/display.c b/src/options/display.c index ef891a5891..d828709b4a 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 655ff1110e..c9f7981342 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 c6daa4c13e..77deb64fc2 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 5eda69e9cf..22482011da 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 1a5693f291..4542eae8e8 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 1d85663b36..dc2d847050 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);