mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-13 02:42:09 +02:00
Common (Format): handles ANSI escapes when padding/truncating variable strings
Fixes #2364
This commit is contained in:
@@ -425,6 +425,33 @@ static bool parseQuickJSString(FFstrbuf* buffer, const char* script, uint32_t sc
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool skipAnsiEscape(FFstrbuf* in, FFstrbuf* out, FFstrbuf* trailingEscape) {
|
||||
if (__builtin_expect(in->chars[0] == '\e' && in->chars[1] == '[', false)) {
|
||||
// skip ANSI escape codes at the start of the string for truncation
|
||||
const char* p = in->chars + 2;
|
||||
while (*p && (ffCharIsDigit(*p) || *p == ';')) {
|
||||
++p;
|
||||
}
|
||||
if (*p && isascii(*p)) {
|
||||
++p;
|
||||
}
|
||||
uint32_t prefixLen = (uint32_t) (p - in->chars);
|
||||
ffStrbufAppendNS(out, prefixLen, in->chars);
|
||||
ffStrbufSubstrAfter(in, prefixLen - 1);
|
||||
|
||||
if (trailingEscape) {
|
||||
// likely have a `CSI m` reset at the end of the string
|
||||
uint32_t iLastEscape = ffStrbufLastIndexC(in, '\e');
|
||||
if (iLastEscape != in->length) {
|
||||
ffStrbufSetNS(trailingEscape, in->length - iLastEscape, in->chars + iLastEscape);
|
||||
ffStrbufSubstrBefore(in, iLastEscape);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool parseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments) {
|
||||
uint32_t argCounter = 0;
|
||||
|
||||
@@ -617,6 +644,8 @@ static bool parseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint3
|
||||
} else if (cSep == '~') {
|
||||
FF_STRBUF_AUTO_DESTROY tempString = ffStrbufCreate();
|
||||
ffFormatAppendFormatArg(&tempString, &arguments[index - 1]);
|
||||
FF_STRBUF_AUTO_DESTROY trailingEscape = ffStrbufCreate();
|
||||
skipAnsiEscape(&tempString, buffer, &trailingEscape);
|
||||
|
||||
char* pEnd = NULL;
|
||||
int32_t start = (int32_t) strtol(pSep + 1, &pEnd, 10);
|
||||
@@ -642,6 +671,10 @@ static bool parseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint3
|
||||
}
|
||||
}
|
||||
|
||||
if (trailingEscape.length > 0) {
|
||||
ffStrbufAppend(buffer, &trailingEscape);
|
||||
}
|
||||
|
||||
if (*pEnd) {
|
||||
*pSep = cSep;
|
||||
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
|
||||
@@ -664,6 +697,9 @@ static bool parseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint3
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY tempString = ffStrbufCreate();
|
||||
ffFormatAppendFormatArg(&tempString, &arguments[index - 1]);
|
||||
FF_STRBUF_AUTO_DESTROY trailingEscape = ffStrbufCreate();
|
||||
skipAnsiEscape(&tempString, buffer, &trailingEscape);
|
||||
|
||||
if (tempString.length == (uint32_t) truncLength) {
|
||||
ffStrbufAppend(buffer, &tempString);
|
||||
} else if (tempString.length > (uint32_t) truncLength) {
|
||||
@@ -689,6 +725,10 @@ static bool parseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint3
|
||||
ffStrbufAppend(buffer, &tempString);
|
||||
}
|
||||
}
|
||||
|
||||
if (trailingEscape.length > 0) {
|
||||
ffStrbufAppend(buffer, &trailingEscape);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,29 @@ int main(void) {
|
||||
VERIFY("output({?1}OK{?}{/1}NOT OK{/})", "", "output(NOT OK)");
|
||||
}
|
||||
|
||||
{
|
||||
VERIFY("output({1:3})", "\e[1m12345", "output(\e[1m123)");
|
||||
VERIFY("output({1:-3})", "\e[1m12345", "output(\e[1m123…)");
|
||||
VERIFY("output({1:3})", "\e[1m12345\e[m", "output(\e[1m123\e[m)");
|
||||
VERIFY("output({1:-3})", "\e[1m12345\e[m", "output(\e[1m123…\e[m)");
|
||||
}
|
||||
|
||||
{
|
||||
VERIFY("output({1<8})", "\e[1m12345", "output(\e[1m12345 )");
|
||||
VERIFY("output({1>8})", "\e[1m12345", "output(\e[1m 12345)");
|
||||
VERIFY("output({1<8})", "\e[1m12345\e[m", "output(\e[1m12345 \e[m)");
|
||||
VERIFY("output({1>8})", "\e[1m12345\e[m", "output(\e[1m 12345\e[m)");
|
||||
VERIFY("output({1<1})", "\e[30;47m12345\e[m", "output(\e[30;47m1\e[m)");
|
||||
}
|
||||
|
||||
{
|
||||
VERIFY("output({1~0})", "\e[1m12345", "output(\e[1m12345)");
|
||||
VERIFY("output({1~1})", "\e[1m12345", "output(\e[1m2345)");
|
||||
VERIFY("output({1~0})", "\e[1m12345\e[m", "output(\e[1m12345\e[m)");
|
||||
VERIFY("output({1~1})", "\e[1m12345\e[m", "output(\e[1m2345\e[m)");
|
||||
VERIFY("output({1~2})", "\e[30;47m12345\e[m", "output(\e[30;47m345\e[m)");
|
||||
}
|
||||
|
||||
#ifndef _WIN32 // Windows doesn't have setenv
|
||||
{
|
||||
ffListInit(&instance.config.display.constants);
|
||||
|
||||
Reference in New Issue
Block a user