mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 18:32:10 +02:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b81c4a04db | |||
| e26a05e3ac | |||
| f08a1fb0b4 | |||
| 2a82009ffe | |||
| e851f3a7ed | |||
| 3a865df09e | |||
| bae80e2932 | |||
| 4445e1e78d | |||
| f0e3d3d8e1 | |||
| a313fd1572 | |||
| 927d44d919 | |||
| 3b9a91e8af | |||
| 70b4582bb6 | |||
| 461552b8d0 | |||
| 0f3db37199 | |||
| 67f16b269a | |||
| 25671fa4b4 | |||
| 4eaa04d4a4 | |||
| 7592885b9f | |||
| 508a3fde36 | |||
| f0273224e0 | |||
| 31e833c02e | |||
| a20d915412 | |||
| d3453de73c | |||
| 79a11c4728 | |||
| 24591417ce | |||
| de6d066fc9 | |||
| 6362c896f8 |
@@ -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 <modules...>` 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:
|
||||
|
||||
+1
-1
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
Vendored
+6
@@ -1,3 +1,9 @@
|
||||
fastfetch (2.57.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.57.1
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 14 Jan 2026 14:00:17 +0800
|
||||
|
||||
fastfetch (2.57.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.57.0
|
||||
|
||||
@@ -1999,7 +1999,7 @@
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"type": {
|
||||
"description": "Print some colored blocks",
|
||||
"description": "Display the terminal's 16-color palette",
|
||||
"const": "colors"
|
||||
},
|
||||
"symbol": {
|
||||
|
||||
@@ -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.
|
||||
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||
{
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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.
|
||||
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
+12
-4
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
@@ -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, "<no implementation provided>");
|
||||
}
|
||||
|
||||
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';
|
||||
if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleType, ':'))
|
||||
continue;
|
||||
|
||||
parseStructureCommand(data->structure.chars + startIndex, genJsonConfig, jsonDoc);
|
||||
|
||||
startIndex = colonIndex + 1;
|
||||
parseStructureCommand(data, moduleType, genJsonConfig);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-10
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
#include "common/io.h"
|
||||
#include "common/smbiosHelper.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
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)
|
||||
|
||||
@@ -2,20 +2,42 @@
|
||||
#include "common/io.h"
|
||||
#include "common/smbiosHelper.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
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(result->type.length)
|
||||
if (ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_type", "/sys/class/dmi/id/chassis_type", &result->type))
|
||||
{
|
||||
const char* typeStr = ffChassisTypeToString((uint32_t) ffStrbufToUInt(&result->type, 9999));
|
||||
if(typeStr)
|
||||
ffStrbufSetS(&result->type, typeStr);
|
||||
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)
|
||||
{
|
||||
const char* typeStr = ffChassisTypeToString((uint32_t) ffStrbufToUInt(&result->type, 9999));
|
||||
if(typeStr)
|
||||
ffStrbufSetStatic(&result->type, typeStr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
+17
-19
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
+23
-13
@@ -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.
|
||||
|
||||
+2
-1
@@ -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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <wayland-util.h>
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -50,9 +50,16 @@ const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE
|
||||
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;
|
||||
|
||||
+81
-64
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+1
-12
@@ -5,12 +5,6 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef FF_USE_SYSTEM_YYJSON
|
||||
#include <yyjson.h>
|
||||
#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
|
||||
|
||||
+4
-1
@@ -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;
|
||||
|
||||
@@ -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████
|
||||
████████████
|
||||
@@ -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"},
|
||||
|
||||
+3
-12
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
+1
-5
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
+2
-1
@@ -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)
|
||||
|
||||
+19
-19
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user