Format: support syntax of padded string

Ref: #1237
This commit is contained in:
李通洲
2024-09-02 15:54:22 +08:00
parent 093940e504
commit 85d89395a9
4 changed files with 150 additions and 13 deletions
+8
View File
@@ -1342,9 +1342,17 @@ if (BUILD_TESTS)
PRIVATE libfastfetch
)
add_executable(fastfetch-test-format
tests/format.c
)
target_link_libraries(fastfetch-test-format
PRIVATE libfastfetch
)
enable_testing()
add_test(NAME test-strbuf COMMAND fastfetch-test-strbuf)
add_test(NAME test-list COMMAND fastfetch-test-list)
add_test(NAME test-format COMMAND fastfetch-test-format)
endif()
##################
+58 -13
View File
@@ -265,18 +265,34 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
continue;
}
int32_t truncLength = INT32_MAX;
char* pColon = memchr(placeholderValue.chars, ':', placeholderValue.length);
if (pColon != NULL)
int32_t truncLength = 0;
char align = '\0';
char* pSep = memchr(placeholderValue.chars, ':', placeholderValue.length);
if (pSep)
align = ':';
else
{
pSep = memchr(placeholderValue.chars, '<', placeholderValue.length);
if (pSep)
align = '<';
else
{
pSep = memchr(placeholderValue.chars, '>', placeholderValue.length);
if (pSep)
align = '>';
}
}
if (pSep)
{
char* pEnd = NULL;
truncLength = (int32_t) strtol(pColon + 1, &pEnd, 10);
truncLength = (int32_t) strtol(pSep + 1, &pEnd, 10);
if (*pEnd != '\0')
{
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
continue;
}
*pColon = '\0';
*pSep = '\0';
}
uint32_t index = getArgumentIndex(placeholderValue.chars, numArgs, arguments);
@@ -287,7 +303,7 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
if (index > numArgs)
{
if (pColon) *pColon = ':';
if (pSep) *pSep = align;
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
continue;
}
@@ -299,14 +315,43 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
truncLength = -truncLength;
}
uint32_t oldLength = buffer->length;
ffFormatAppendFormatArg(buffer, &arguments[index - 1]);
if (buffer->length - oldLength > (uint32_t) truncLength)
if (!align)
ffFormatAppendFormatArg(buffer, &arguments[index - 1]);
else
{
ffStrbufSubstrBefore(buffer, oldLength + (uint32_t) truncLength);
ffStrbufTrimRightSpace(buffer);
if (ellipsis)
ffStrbufAppendS(buffer, "");
ffStrbufClear(&placeholderValue);
ffFormatAppendFormatArg(&placeholderValue, &arguments[index - 1]);
if (placeholderValue.length == (uint32_t) truncLength)
ffStrbufAppend(buffer, &placeholderValue);
else if (placeholderValue.length > (uint32_t) truncLength)
{
if (align == ':')
{
ffStrbufSubstrBefore(&placeholderValue, (uint32_t) truncLength);
ffStrbufTrimRightSpace(&placeholderValue);
}
else
ffStrbufSubstrBefore(&placeholderValue, (uint32_t) (!ellipsis? truncLength : truncLength - 1));
ffStrbufAppend(buffer, &placeholderValue);
if (ellipsis)
ffStrbufAppendS(buffer, "");
}
else if (align == ':')
ffStrbufAppend(buffer, &placeholderValue);
else
{
if (align == '<')
{
ffStrbufAppend(buffer, &placeholderValue);
ffStrbufAppendNC(buffer, (uint32_t) truncLength - placeholderValue.length, ' ');
}
else
{
ffStrbufAppendNC(buffer, (uint32_t) truncLength - placeholderValue.length, ' ');
ffStrbufAppend(buffer, &placeholderValue);
}
}
}
}
+4
View File
@@ -13,6 +13,10 @@ For example: "--title-format '{user-name:5}'" will truncate user name into 5-len
If '<trunc-length>' is negative, an ellipsis … will be appended at the end when the original string is truncated.
Note: The string length is counted in raw bytes. Multi-byte unicode characters and ANSI escape codes are not taken into account.
In 2.23.0 or newer, `<` or `>` can be specified instead of `:` to set a left or right padding.
For example: "--title-format '{user-name<20}'" will generate `<user-name> `;
"--title-format '{user-name>20}'" will generate ` <user-name>`
If the value index is missing, meaning the placeholder is "{}", an internal counter sets the value index.
This means that the format string "Values: {1} ({2})" is equivalent to "Values: {} ({})".
Note that this counter only counts empty placeholders, so the format string "{2} {} {}" will contain the second value, then the first, and then the second again.
+80
View File
@@ -0,0 +1,80 @@
#include "common/format.h"
#include "util/textModifier.h"
#include "fastfetch.h"
static void verify(const char* format, const char* arg, const char* expected, int lineNo)
{
FF_STRBUF_AUTO_DESTROY result = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY formatter = ffStrbufCreateStatic(format);
const FFformatarg arguments[] = {
{ .type = FF_FORMAT_ARG_TYPE_STRING, arg }
};
ffParseFormatString(&result, &formatter, 1, arguments);
if (!ffStrbufEqualS(&result, expected))
{
fprintf(stderr, FASTFETCH_TEXT_MODIFIER_ERROR "[%d] %s: expected \"%s\", got \"%s\"\n" FASTFETCH_TEXT_MODIFIER_RESET, lineNo, format, expected, result.chars);
exit(1);
}
}
#define VERIFY(format, argument, expected) verify((format), (argument), (expected), __LINE__)
int main(void)
{
instance.config.display.pipe = true;
{
VERIFY("output({})", "12345 67890", "output(12345 67890)");
VERIFY("output({1})", "12345 67890", "output(12345 67890)");
VERIFY("output({})", "", "output()");
VERIFY("output({1})", "", "output()");
}
{
VERIFY("output({1:20})", "12345 67890", "output(12345 67890)");
VERIFY("output({1:11})", "12345 67890", "output(12345 67890)");
VERIFY("output({1:-11})", "12345 67890", "output(12345 67890)");
VERIFY("output({1:6})", "12345 67890", "output(12345)");
VERIFY("output({:6})", "12345 67890", "output(12345)");
VERIFY("output({:-6})", "12345 67890", "output(12345…)");
VERIFY("output({:0})", "12345 67890", "output()");
VERIFY("output({:})", "12345 67890", "output()");
}
{
VERIFY("output({1<20})", "12345 67890", "output(12345 67890 )");
VERIFY("output({1<-20})", "12345 67890", "output(12345 67890 )");
VERIFY("output({1<11})", "12345 67890", "output(12345 67890)");
VERIFY("output({1<-11})", "12345 67890", "output(12345 67890)");
VERIFY("output({1<6})", "12345 67890", "output(12345 )");
VERIFY("output({<6})", "12345 67890", "output(12345 )");
VERIFY("output({<-6})", "12345 67890", "output(12345…)");
VERIFY("output({<0})", "12345 67890", "output()");
VERIFY("output({<})", "12345 67890", "output()");
}
{
VERIFY("output({1>20})", "12345 67890", "output( 12345 67890)");
VERIFY("output({1>-20})", "12345 67890", "output( 12345 67890)");
VERIFY("output({1>11})", "12345 67890", "output(12345 67890)");
VERIFY("output({1>-11})", "12345 67890", "output(12345 67890)");
VERIFY("output({1>6})", "12345 67890", "output(12345 )");
VERIFY("output({>6})", "12345 67890", "output(12345 )");
VERIFY("output({>-6})", "12345 67890", "output(12345…)");
VERIFY("output({>0})", "12345 67890", "output()");
VERIFY("output({>})", "12345 67890", "output()");
}
{
VERIFY("output({1n>20})", "12345 67890", "output({1n>20})");
VERIFY("output({120})", "12345 67890", "output({120})");
VERIFY("output({1:11})", "", "output()");
}
{
VERIFY("output({1:20}{1<20}{1>20})", "12345 67890", "output(12345 6789012345 67890 12345 67890)");
}
//Success
puts("\033[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET);
}