diff options
| author | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
|---|---|---|
| committer | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
| commit | 76424950e373d3b04ac3dd13019151bfba3e8423 (patch) | |
| tree | 4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/common/impl/percent.c | |
Add the files
Diffstat (limited to 'src/common/impl/percent.c')
| -rw-r--r-- | src/common/impl/percent.c | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/src/common/impl/percent.c b/src/common/impl/percent.c new file mode 100644 index 0000000..266588c --- /dev/null +++ b/src/common/impl/percent.c @@ -0,0 +1,293 @@ +#include "fastfetch.h" +#include "common/percent.h" +#include "common/color.h" +#include "common/option.h" +#include "common/jsonconfig.h" +#include "common/textModifier.h" +#include "common/strutil.h" + +static void appendOutputColor(FFstrbuf* buffer, const FFModuleArgs* module) { + if (module->outputColor.length) { + ffStrbufAppendF(buffer, "\e[%sm", module->outputColor.chars); + } else if (instance.config.display.colorOutput.length) { + ffStrbufAppendF(buffer, "\e[%sm", instance.config.display.colorOutput.chars); + } +} + +const char* ffPercentParseTypeJsonConfig(yyjson_val* jsonVal, FFPercentageTypeFlags* result) { + if (yyjson_is_uint(jsonVal)) { + *result = (FFPercentageTypeFlags) yyjson_get_uint(jsonVal); + return NULL; + } + if (yyjson_is_arr(jsonVal)) { + FFPercentageTypeFlags flags = 0; + + yyjson_val* item; + size_t idx, max; + yyjson_arr_foreach (jsonVal, idx, max, item) { + const char* flag = yyjson_get_str(item); + if (!flag) { + return "Error: percent.type: invalid flag string"; + } + if (ffStrEqualsIgnCase(flag, "num")) { + flags |= FF_PERCENTAGE_TYPE_NUM_BIT; + } else if (ffStrEqualsIgnCase(flag, "bar")) { + flags |= FF_PERCENTAGE_TYPE_BAR_BIT; + } else if (ffStrEqualsIgnCase(flag, "hide-others")) { + flags |= FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT; + } else if (ffStrEqualsIgnCase(flag, "num-color")) { + flags |= FF_PERCENTAGE_TYPE_NUM_COLOR_BIT; + } else if (ffStrEqualsIgnCase(flag, "bar-monochrome")) { + flags |= FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT; + } else { + return "Error: percent.type: unknown flag string"; + } + } + + *result = flags; + return NULL; + } + + return "Error: usage: percent.type must be a number or an array of strings"; +} + +void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConfig config, const FFModuleArgs* module) { + uint8_t green = config.green, yellow = config.yellow; + assert(green <= 100 && yellow <= 100); + + const FFOptionsDisplay* options = &instance.config.display; + + const bool borderAsValue = options->barBorderLeftElapsed.length && options->barBorderRightElapsed.length; + + if (!borderAsValue && options->barBorderLeft.length) { + if (!options->pipe && options->barColorBorder.length > 0) { + ffStrbufAppendF(buffer, "\e[%sm", options->barColorBorder.chars); + } + ffStrbufAppend(buffer, &options->barBorderLeft); + } + + if (percent == -DBL_MAX) { + // Use total color for simplification + if (!options->pipe && options->barColorTotal.length > 0) { + ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m"); + } + + for (uint8_t i = 0; i < options->barWidth; ++i) { + ffStrbufAppend(buffer, borderAsValue && i == 0 ? &options->barBorderLeft : borderAsValue && i == options->barWidth - 1 ? &options->barBorderRight + : &options->barCharTotal); + } + } else { + const char* colorGreen = options->percentColorGreen.chars; + const char* colorYellow = options->percentColorYellow.chars; + const char* colorRed = options->percentColorRed.chars; + + FFPercentageTypeFlags percentType = config.type == 0 ? options->percentType : config.type; + + uint8_t blocksPercent = (uint8_t) (percent / 100.0 * options->barWidth + 0.5); + assert(blocksPercent <= options->barWidth); + + bool autoColorElapsed = ffStrbufIgnCaseEqualS(&options->barColorElapsed, "auto"); + + bool monochrome = (percentType & FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT) || !autoColorElapsed; + if (!options->pipe && options->barColorElapsed.length > 0 && monochrome) { + const char* color = NULL; + if (!autoColorElapsed) { + color = options->barColorElapsed.chars; + } else if (green <= yellow) { + if (percent < green) { + color = colorGreen; + } else if (percent < yellow) { + color = colorYellow; + } else { + color = colorRed; + } + } else { + if (percent < yellow) { + color = colorRed; + } else if (percent < green) { + color = colorYellow; + } else { + color = colorGreen; + } + } + ffStrbufAppendF(buffer, "\e[%sm", color); + } + for (uint8_t i = 0; i < blocksPercent; ++i) { + if (!options->pipe && options->barColorElapsed.length > 0 && !monochrome) { + uint32_t section1Begin = (uint32_t) ((green <= yellow ? green : yellow) / 100.0 * options->barWidth + 0.5); + uint32_t section2Begin = (uint32_t) ((green > yellow ? green : yellow) / 100.0 * options->barWidth + 0.5); + if (i == section2Begin) { + ffStrbufAppendF(buffer, "\e[%sm", (green > yellow ? colorGreen : colorRed)); + } else if (i == section1Begin) { + ffStrbufAppendF(buffer, "\e[%sm", colorYellow); + } else if (i == 0) { + ffStrbufAppendF(buffer, "\e[%sm", (green <= yellow ? colorGreen : colorRed)); + } + } + ffStrbufAppend(buffer, borderAsValue && i == 0 ? &options->barBorderLeftElapsed : borderAsValue && i == options->barWidth - 1 ? &options->barBorderRightElapsed + : &options->barCharElapsed); + } + + if (blocksPercent < options->barWidth) { + if (!options->pipe && options->barColorTotal.length > 0) { + ffStrbufAppendF(buffer, "\e[%sm", options->barColorTotal.chars); + } + for (uint8_t i = blocksPercent; i < options->barWidth; ++i) { + ffStrbufAppend(buffer, borderAsValue && i == 0 ? &options->barBorderLeft : borderAsValue && i == options->barWidth - 1 ? &options->barBorderRight + : &options->barCharTotal); + } + } + } + + if (!borderAsValue && options->barBorderRight.length) { + if (!options->pipe && options->barColorBorder.length > 0) { + ffStrbufAppendF(buffer, "\e[%sm", options->barColorBorder.chars); + } + ffStrbufAppend(buffer, &options->barBorderRight); + } + + if (!options->pipe && (options->barColorElapsed.length > 0 || options->barColorTotal.length > 0 || options->barColorBorder.length > 0)) { + ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET); + appendOutputColor(buffer, module); + } +} + +void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConfig config, bool parentheses, const FFModuleArgs* module) { + uint8_t green = config.green, yellow = config.yellow; + assert(green <= 100 && yellow <= 100); + + const FFOptionsDisplay* options = &instance.config.display; + FFPercentageTypeFlags percentType = config.type == 0 ? options->percentType : config.type; + + bool colored = !!(percentType & FF_PERCENTAGE_TYPE_NUM_COLOR_BIT); + + if (parentheses) { + ffStrbufAppendC(buffer, '('); + } + + if (colored && !options->pipe) { + const char* colorGreen = options->percentColorGreen.chars; + const char* colorYellow = options->percentColorYellow.chars; + const char* colorRed = options->percentColorRed.chars; + + if (percent == -DBL_MAX) { + ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m"); + } else if (green <= yellow) { + if (percent > yellow) { + ffStrbufAppendF(buffer, "\e[%sm", colorRed); + } else if (percent > green) { + ffStrbufAppendF(buffer, "\e[%sm", colorYellow); + } else { + ffStrbufAppendF(buffer, "\e[%sm", colorGreen); + } + } else { + if (percent < yellow) { + ffStrbufAppendF(buffer, "\e[%sm", colorRed); + } else if (percent < green) { + ffStrbufAppendF(buffer, "\e[%sm", colorYellow); + } else { + ffStrbufAppendF(buffer, "\e[%sm", colorGreen); + } + } + } + if (percent == -DBL_MAX) { + ffStrbufAppendS(buffer, "-"); + } else { + ffStrbufAppendF(buffer, "%*.*f%s%%", options->percentWidth, options->percentNdigits, percent, options->percentSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : ""); + } + + if (colored && !options->pipe) { + ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET); + appendOutputColor(buffer, module); + } + + if (parentheses) { + ffStrbufAppendC(buffer, ')'); + } +} + +bool ffPercentParseCommandOptions(const char* key, const char* subkey, const char* value, FFPercentageModuleConfig* config) { + if (!ffStrStartsWithIgnCase(subkey, "percent-")) { + return false; + } + + subkey += strlen("percent-"); + + if (ffStrEqualsIgnCase(subkey, "green")) { + uint32_t num = ffOptionParseUInt32(key, value); + if (num > 100) { + fprintf(stderr, "Error: usage: %s must be between 0 and 100\n", key); + exit(480); + } + config->green = (uint8_t) num; + return true; + } + + if (ffStrEqualsIgnCase(subkey, "yellow")) { + uint32_t num = ffOptionParseUInt32(key, value); + if (num > 100) { + fprintf(stderr, "Error: usage: %s must be between 0 and 100\n", key); + exit(480); + } + config->yellow = (uint8_t) num; + return true; + } + + if (ffStrEqualsIgnCase(subkey, "type")) { + config->type = (FFPercentageTypeFlags) ffOptionParseUInt32(key, value); + return true; + } + + return false; +} + +bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageModuleConfig* config) { + assert(key); + + if (!unsafe_yyjson_equals_str(key, "percent")) { + return false; + } + + if (!yyjson_is_obj(value)) { + fprintf(stderr, "Error: usage: %s must be an object\n", unsafe_yyjson_get_str(key)); + exit(480); + } + + yyjson_val* greenVal = yyjson_obj_get(value, "green"); + if (greenVal) { + int num = yyjson_get_int(greenVal); + if (num < 0 || num > 100) { + fputs("Error: usage: percent.green must be between 0 and 100\n", stderr); + exit(480); + } + config->green = (uint8_t) num; + } + + yyjson_val* yellowVal = yyjson_obj_get(value, "yellow"); + if (yellowVal) { + int num = yyjson_get_int(yellowVal); + if (num < 0 || num > 100) { + fputs("Error: usage: percent.yellow must be between 0 and 100\n", stderr); + exit(480); + } + config->yellow = (uint8_t) num; + } + + yyjson_val* typeVal = yyjson_obj_get(value, "type"); + if (typeVal) { + const char* error = ffPercentParseTypeJsonConfig(typeVal, &config->type); + if (error) { + fputs(error, stderr); + exit(480); + } + } + + return true; +} + +void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig config) { + yyjson_mut_val* percent = yyjson_mut_obj_add_obj(doc, module, "percent"); + yyjson_mut_obj_add_uint(doc, percent, "green", config.green); + yyjson_mut_obj_add_uint(doc, percent, "yellow", config.yellow); + yyjson_mut_obj_add_uint(doc, percent, "type", config.type); +} |