ohmu
·
2026-10-15
1#include "fastfetch.h"
2#include "common/printing.h"
3#include "common/textModifier.h"
4#include "logo/logo.h"
5
6void ffPrintLogoAndKey(const char* moduleName, uint32_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType) {
7 ffLogoPrintLine();
8
9 // This is used by --set-keyless, in this case we want neither the module name nor the separator
10 if (moduleName == nullptr) {
11 return;
12 }
13
14 // This is used as a magic value for hiding keys
15 if (!(moduleArgs && ffStrbufEqualS(&moduleArgs->key, " ")) && instance.config.display.keyType != FF_MODULE_KEY_TYPE_NONE) {
16 ffPrintCharTimes(' ', instance.config.display.keyPaddingLeft);
17
18 if (!instance.config.display.pipe) {
19 fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
20 if (instance.config.display.brightColor) {
21 fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
22 }
23
24 if (moduleArgs && !(printType & FF_PRINT_TYPE_NO_CUSTOM_KEY_COLOR) && moduleArgs->keyColor.length > 0) {
25 ffPrintColor(&moduleArgs->keyColor);
26 } else {
27 ffPrintColor(&instance.config.display.colorKeys);
28 }
29 }
30
31 if (instance.config.display.keyType & FF_MODULE_KEY_TYPE_ICON && moduleArgs && moduleArgs->keyIcon.length > 0) {
32 ffStrbufWriteTo(&moduleArgs->keyIcon, stdout);
33 }
34
35 if (instance.config.display.keyType & FF_MODULE_KEY_TYPE_STRING) {
36 ffPrintCharTimes(' ', instance.config.display.keyType >> FF_MODULE_KEY_TYPE_SPACE_SHIFT);
37
38 // nullptr check is required for modules with custom keys, e.g. disk with the folder path
39 if ((printType & FF_PRINT_TYPE_NO_CUSTOM_KEY) || !moduleArgs || moduleArgs->key.length == 0) {
40 fputs(moduleName, stdout);
41
42 if (moduleIndex > 0) {
43 printf(" %u", moduleIndex);
44 }
45 } else {
46 FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate();
47 FF_PARSE_FORMAT_STRING_CHECKED(&key, &moduleArgs->key, ((FFformatarg[]) {
48 FF_ARG(moduleIndex, "index"),
49 FF_ARG(moduleArgs->keyIcon, "icon"),
50 FF_ARG(moduleName, "module-name"),
51 }));
52 ffStrbufWriteTo(&key, stdout);
53 }
54 }
55
56 if (!instance.config.display.pipe) {
57 fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
58 ffPrintColor(&instance.config.display.colorSeparator);
59 }
60
61 ffStrbufWriteTo(&instance.config.display.keyValueSeparator, stdout);
62
63 if (!instance.config.display.pipe && instance.config.display.colorSeparator.length) {
64 fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
65 }
66
67 if (!(printType & FF_PRINT_TYPE_NO_CUSTOM_KEY_WIDTH)) {
68 uint32_t keyWidth = moduleArgs && moduleArgs->keyWidth > 0 ? moduleArgs->keyWidth : instance.config.display.keyWidth;
69 if (keyWidth > 0) {
70 printf("\e[%uG", (unsigned) (keyWidth + instance.state.logoWidth));
71 }
72 }
73 }
74
75 if (!instance.config.display.pipe) {
76 fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
77 if (moduleArgs && moduleArgs->outputColor.length) {
78 ffPrintColor(&moduleArgs->outputColor);
79 } else if (instance.config.display.colorOutput.length) {
80 ffPrintColor(&instance.config.display.colorOutput);
81 }
82 }
83}
84
85bool ffPrintFormat(const char* moduleName, uint32_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, uint32_t numArgs, const FFformatarg* arguments) {
86 FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
87 bool success;
88 if (__builtin_expect(moduleArgs != nullptr, 1)) {
89 success = ffParseFormatString(&buffer, &moduleArgs->outputFormat, numArgs, arguments);
90 } else {
91 ffStrbufSetStatic(&buffer, "undefined format");
92 success = false;
93 }
94
95 if (success) {
96 ffPrintLogoAndKey(moduleName, moduleIndex, moduleArgs, printType);
97 ffStrbufPutTo(&buffer, stdout);
98 } else {
99 ffPrintError(moduleName, moduleIndex, moduleArgs, printType, "%s", buffer.chars);
100 }
101
102 return success;
103}
104
105void ffPrintError(const char* moduleName, uint32_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...) {
106 if (!instance.config.display.showErrors) {
107 return;
108 }
109
110 ffPrintLogoAndKey(moduleName, moduleIndex, moduleArgs, printType);
111
112 if (!instance.config.display.pipe) {
113 fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stdout);
114 }
115
116 va_list arguments;
117 va_start(arguments, message);
118 vprintf(message, arguments);
119 va_end(arguments);
120
121 if (!instance.config.display.pipe) {
122 fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
123 }
124
125 putchar('\n');
126}
127
128void ffPrintColor(const FFstrbuf* colorValue) {
129 // If the color is not set, this would reset in \033[m, which resets everything.
130 // So we only print it, if the main color is at least one char.
131 if (colorValue->length == 0) {
132 return;
133 }
134
135 printf("\e[%sm", colorValue->chars);
136}
137
138void ffPrintCharTimes(char c, uint32_t times) {
139 if (times == 0) {
140 return;
141 }
142
143 if (times == 1) {
144 putchar(c);
145 return;
146 }
147
148 char str[32];
149 memset(str, c, sizeof(str)); // 2 instructions when compiling with AVX2 enabled
150 for (uint32_t i = sizeof(str); i <= times; i += (uint32_t) sizeof(str)) {
151 fwrite(str, 1, sizeof(str), stdout);
152 }
153 uint32_t remaining = times % sizeof(str);
154 if (remaining > 0) {
155 fwrite(str, 1, remaining, stdout);
156 }
157}