mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-11-07 21:50:08 +01:00
Global: init --format json support (#527)
This commit is contained in:
@@ -1,7 +1,26 @@
|
||||
#include "commandoption.h"
|
||||
#include "common/printing.h"
|
||||
#include "common/time.h"
|
||||
#include "fastfetch_datatext.h"
|
||||
#include "modules/modules.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
static inline yyjson_mut_val* genJson(FFModuleBaseInfo* baseInfo)
|
||||
{
|
||||
yyjson_mut_doc* doc = instance.state.resultDoc;
|
||||
if (__builtin_expect(!doc, true)) return NULL;
|
||||
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root);
|
||||
yyjson_mut_obj_add_str(doc, module, "type", baseInfo->name);
|
||||
if (baseInfo->generateJson)
|
||||
baseInfo->generateJson(baseInfo, doc, module);
|
||||
else
|
||||
yyjson_mut_obj_add_str(doc, module, "error", "Unsupported for JSON format");
|
||||
return module;
|
||||
}
|
||||
|
||||
bool ffParseModuleCommand(const char* type)
|
||||
{
|
||||
@@ -12,7 +31,8 @@ bool ffParseModuleCommand(const char* type)
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
if (ffStrEqualsIgnCase(type, baseInfo->name))
|
||||
{
|
||||
baseInfo->printModule(baseInfo);
|
||||
if (!genJson(baseInfo))
|
||||
baseInfo->printModule(baseInfo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -30,3 +50,76 @@ bool ffParseModuleOptions(const char* key, const char* value)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffPrepareCommandOption(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);
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_CPUUSAGE_MODULE_NAME))
|
||||
ffPrepareCPUUsage();
|
||||
|
||||
if(instance.config.multithreading)
|
||||
{
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_PUBLICIP_MODULE_NAME))
|
||||
ffPreparePublicIp(&instance.config.publicIP);
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_WEATHER_MODULE_NAME))
|
||||
ffPrepareWeather(&instance.config.weather);
|
||||
}
|
||||
}
|
||||
|
||||
static void parseStructureCommand(const char* line, FFlist* customValues)
|
||||
{
|
||||
// handle `--set` and `--set-keyless`
|
||||
FF_LIST_FOR_EACH(FFCustomValue, customValue, *customValues)
|
||||
{
|
||||
if (ffStrbufEqualS(&customValue->key, line))
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyCustomOptions))) FFCustomOptions options;
|
||||
ffInitCustomOptions(&options);
|
||||
if (customValue->printKey)
|
||||
ffStrbufAppend(&options.moduleArgs.key, &customValue->key);
|
||||
ffStrbufAppend(&options.moduleArgs.outputFormat, &customValue->value);
|
||||
ffPrintCustom(&options);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(!ffParseModuleCommand(line))
|
||||
ffPrintErrorString(line, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "<no implementation provided>");
|
||||
}
|
||||
|
||||
void ffPrintCommandOption(FFdata* data)
|
||||
{
|
||||
//Parse the structure and call the modules
|
||||
uint32_t startIndex = 0;
|
||||
while (startIndex < data->structure.length)
|
||||
{
|
||||
uint32_t colonIndex = ffStrbufNextIndexC(&data->structure, startIndex, ':');
|
||||
data->structure.chars[colonIndex] = '\0';
|
||||
|
||||
uint64_t ms = 0;
|
||||
if(__builtin_expect(instance.config.stat, false))
|
||||
ms = ffTimeGetTick();
|
||||
|
||||
parseStructureCommand(data->structure.chars + startIndex, &data->customValues);
|
||||
|
||||
if(__builtin_expect(instance.config.stat, false))
|
||||
{
|
||||
char str[32];
|
||||
int len = snprintf(str, sizeof str, "%" PRIu64 "ms", ffTimeGetTick() - ms);
|
||||
if(instance.config.pipe)
|
||||
puts(str);
|
||||
else
|
||||
printf("\033[s\033[1A\033[9999999C\033[%dD%s\033[u", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (!instance.config.noBuffer) fflush(stdout);
|
||||
#endif
|
||||
|
||||
startIndex = colonIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,24 @@
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
typedef struct FFCustomValue
|
||||
{
|
||||
bool printKey;
|
||||
FFstrbuf key;
|
||||
FFstrbuf value;
|
||||
} FFCustomValue;
|
||||
|
||||
// Things only needed by fastfetch
|
||||
typedef struct FFdata
|
||||
{
|
||||
FFstrbuf structure;
|
||||
FFlist customValues; // List of FFCustomValue
|
||||
bool loadUserConfig;
|
||||
} FFdata;
|
||||
|
||||
bool ffParseModuleCommand(const char* type);
|
||||
bool ffParseModuleOptions(const char* key, const char* value);
|
||||
void ffPrepareCommandOption(FFdata* data);
|
||||
void ffPrintCommandOption(FFdata* data);
|
||||
|
||||
#endif
|
||||
|
||||
+5
-3
@@ -27,6 +27,7 @@ static void initState(FFstate* state)
|
||||
|
||||
ffPlatformInit(&state->platform);
|
||||
state->configDoc = NULL;
|
||||
state->resultDoc = NULL;
|
||||
}
|
||||
|
||||
static void defaultConfig(void)
|
||||
@@ -234,8 +235,8 @@ void ffStart(void)
|
||||
startDetectionThreads();
|
||||
#endif
|
||||
|
||||
ffDisableLinewrap = instance.config.disableLinewrap && !instance.config.pipe;
|
||||
ffHideCursor = instance.config.hideCursor && !instance.config.pipe;
|
||||
ffDisableLinewrap = instance.config.disableLinewrap && !instance.config.pipe && !instance.state.resultDoc;
|
||||
ffHideCursor = instance.config.hideCursor && !instance.config.pipe && !instance.state.resultDoc;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!instance.config.noBuffer) setvbuf(stdout, NULL, _IOFBF, 4096);
|
||||
@@ -254,7 +255,7 @@ void ffStart(void)
|
||||
#endif
|
||||
|
||||
//reset everything to default before we start printing
|
||||
if(!instance.config.pipe)
|
||||
if(!instance.config.pipe && !instance.state.resultDoc)
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
|
||||
if(ffHideCursor)
|
||||
@@ -375,6 +376,7 @@ static void destroyState(void)
|
||||
{
|
||||
ffPlatformDestroy(&instance.state.platform);
|
||||
yyjson_doc_free(instance.state.configDoc);
|
||||
yyjson_mut_doc_free(instance.state.resultDoc);
|
||||
}
|
||||
|
||||
void ffDestroyInstance(void)
|
||||
|
||||
+33
-7
@@ -70,6 +70,20 @@ const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair p
|
||||
return "Invalid enum value type; must be a string or integer";
|
||||
}
|
||||
|
||||
static inline yyjson_mut_val* genJson(FFModuleBaseInfo* baseInfo)
|
||||
{
|
||||
yyjson_mut_doc* doc = instance.state.resultDoc;
|
||||
if (__builtin_expect(!doc, true)) return NULL;
|
||||
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root);
|
||||
yyjson_mut_obj_add_str(doc, module, "type", baseInfo->name);
|
||||
if (baseInfo->generateJson)
|
||||
baseInfo->generateJson(baseInfo, doc, module);
|
||||
else
|
||||
yyjson_mut_obj_add_str(doc, module, "error", "Unsupported for JSON format");
|
||||
return module;
|
||||
}
|
||||
|
||||
static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal)
|
||||
{
|
||||
if(!isalpha(type[0])) return false;
|
||||
@@ -80,7 +94,8 @@ static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal)
|
||||
if (ffStrEqualsIgnCase(type, baseInfo->name))
|
||||
{
|
||||
if (jsonVal) baseInfo->parseJsonObject(baseInfo, jsonVal);
|
||||
baseInfo->printModule(baseInfo);
|
||||
if (!genJson(baseInfo))
|
||||
baseInfo->printModule(baseInfo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -128,6 +143,8 @@ static const char* printJsonConfig(bool prepare)
|
||||
if (!modules) return NULL;
|
||||
if (!yyjson_is_arr(modules)) return "Property 'modules' must be an array of strings or objects";
|
||||
|
||||
yyjson_mut_doc* resultDoc = instance.state.resultDoc;
|
||||
|
||||
yyjson_val* item;
|
||||
size_t idx, max;
|
||||
yyjson_arr_foreach(modules, idx, max, item)
|
||||
@@ -157,16 +174,25 @@ static const char* printJsonConfig(bool prepare)
|
||||
|
||||
if(!prepare && instance.config.stat)
|
||||
{
|
||||
char str[32];
|
||||
int len = snprintf(str, sizeof str, "%" PRIu64 "ms", ffTimeGetTick() - ms);
|
||||
if(instance.config.pipe)
|
||||
puts(str);
|
||||
ms = ffTimeGetTick() - ms;
|
||||
if (resultDoc)
|
||||
{
|
||||
yyjson_mut_val* moduleJson = yyjson_mut_arr_get_last(resultDoc->root);
|
||||
yyjson_mut_obj_add_uint(resultDoc, moduleJson, "stat", ms);
|
||||
}
|
||||
else
|
||||
printf("\033[s\033[1A\033[9999999C\033[%dD%s\033[u", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
{
|
||||
char str[32];
|
||||
int len = snprintf(str, sizeof str, "%" PRIu64 "ms", ms);
|
||||
if(instance.config.pipe)
|
||||
puts(str);
|
||||
else
|
||||
printf("\033[s\033[1A\033[9999999C\033[%dD%s\033[u", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (!instance.config.noBuffer) fflush(stdout);
|
||||
if (!instance.config.noBuffer && !resultDoc) fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -8,3 +8,10 @@ void ffPrintJsonConfig(bool prepare);
|
||||
const char* ffParseGeneralJsonConfig(void);
|
||||
const char* ffParseDisplayJsonConfig(void);
|
||||
const char* ffParseLibraryJsonConfig(void);
|
||||
|
||||
yyjson_api_inline bool yyjson_mut_obj_add_strbuf(yyjson_mut_doc *doc,
|
||||
yyjson_mut_val *obj,
|
||||
const char *_key,
|
||||
FFstrbuf* buf) {
|
||||
return yyjson_mut_obj_add_strncpy(doc, obj, _key, buf->chars, buf->length);
|
||||
}
|
||||
|
||||
+6
-1
@@ -3,6 +3,8 @@
|
||||
#include "util/FFstrbuf.h"
|
||||
|
||||
struct yyjson_val;
|
||||
struct yyjson_mut_doc;
|
||||
struct yyjson_mut_val;
|
||||
|
||||
// Must be the first field of FFModuleOptions
|
||||
typedef struct FFModuleBaseInfo
|
||||
@@ -11,6 +13,7 @@ typedef struct FFModuleBaseInfo
|
||||
bool (*parseCommandOptions)(void* options, const char* key, const char* value);
|
||||
void (*parseJsonObject)(void* options, struct yyjson_val *module);
|
||||
void (*printModule)(void* options);
|
||||
void (*generateJson)(void* options, struct yyjson_mut_doc* doc, struct yyjson_mut_val* module);
|
||||
} FFModuleBaseInfo;
|
||||
|
||||
static inline void ffOptionInitModuleBaseInfo(
|
||||
@@ -18,13 +21,15 @@ static inline void ffOptionInitModuleBaseInfo(
|
||||
const char* name,
|
||||
void* parseCommandOptions, // bool (*const parseCommandOptions)(void* options, const char* key, const char* value)
|
||||
void* parseJsonObject, // void (*const parseJsonObject)(void* options, yyjson_val *module)
|
||||
void* printModule // void (*const printModule)(void* options)
|
||||
void* printModule, // void (*const printModule)(void* options)
|
||||
void* generateJson // void (*const generateJson)(void* options, yyjson_mut_doc* doc, yyjson_mut_val* obj)
|
||||
)
|
||||
{
|
||||
baseInfo->name = name;
|
||||
baseInfo->parseCommandOptions = (__typeof__(baseInfo->parseCommandOptions)) parseCommandOptions;
|
||||
baseInfo->parseJsonObject = (__typeof__(baseInfo->parseJsonObject)) parseJsonObject;
|
||||
baseInfo->printModule = (__typeof__(baseInfo->printModule)) printModule;
|
||||
baseInfo->generateJson = (__typeof__(baseInfo->generateJson)) generateJson;
|
||||
}
|
||||
|
||||
typedef struct FFModuleArgs
|
||||
|
||||
Reference in New Issue
Block a user