string-util: pass ANSI sequences through unchanged
Cutting off in the middle may leave the terminal in a bad state, breaking further output. But we don't know what a given ANSI sequence does, e.g. ANSI_NORMAL should not be skipped. But it is also nice to keep various sequences intact, so that if we had part of the string in blue, and we cut out the beginning of the blue part, we still want to keep the remainder in color. So let's just pass them through, stripping out the characters that take up actual space. Also, use memcpy_safe as we may end up copying zero bytes when ellipsizing at the start/end of a string. Fixes: #24502 This also fixes an ugliness where we would ellipsize string with ANSI sequences too much, leading to output that was narrower on screen than the requested length: Starting AAAAAAAAAAAAAAAAAAAAA.service Starting BBBBBBBBBBBBBBBBBBBBB.service Starting LONG…ER.service Co-authored-by: Jan Janssen <medhefgo@web.de>
This commit is contained in:
co-authored by
Jan Janssen
parent
d9c72e5419
commit
cb558ab222
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "constants.h"
|
||||
#include "escape.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
@@ -115,4 +116,44 @@ TEST(ellipsize) {
|
||||
test_ellipsize_one("shórt");
|
||||
}
|
||||
|
||||
TEST(ellipsize_ansi) {
|
||||
const char *s = ANSI_HIGHLIGHT_YELLOW_UNDERLINE "yęllow"
|
||||
ANSI_HIGHLIGHT_GREY_UNDERLINE "grěy"
|
||||
ANSI_HIGHLIGHT_BLUE_UNDERLINE "blue"
|
||||
ANSI_NORMAL "nórmął";
|
||||
size_t len = strlen(s);
|
||||
|
||||
for (unsigned percent = 0; percent <= 100; percent += 15)
|
||||
for (ssize_t x = 21; x >= 0; x--) {
|
||||
_cleanup_free_ char *t = ellipsize_mem(s, len, x, percent);
|
||||
printf("%02zd: \"%s\"\n", x, t);
|
||||
assert_se(utf8_is_valid(t));
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
_cleanup_free_ char *e = cescape(t);
|
||||
printf(" : \"%s\"\n", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ellipsize_ansi_cats) {
|
||||
_cleanup_free_ char *e, *f, *g, *h;
|
||||
|
||||
/* Make sure we don't cut off in the middle of an ANSI escape sequence. */
|
||||
|
||||
e = ellipsize("01" ANSI_NORMAL "23", 4, 0);
|
||||
puts(e);
|
||||
assert_se(streq(e, "01" ANSI_NORMAL "23"));
|
||||
f = ellipsize("ab" ANSI_NORMAL "cd", 4, 90);
|
||||
puts(f);
|
||||
assert_se(streq(f, "ab" ANSI_NORMAL "cd"));
|
||||
|
||||
g = ellipsize("🐱🐱" ANSI_NORMAL "🐱🐱" ANSI_NORMAL, 5, 0);
|
||||
puts(g);
|
||||
assert_se(streq(g, "…" ANSI_NORMAL "🐱🐱" ANSI_NORMAL));
|
||||
h = ellipsize("🐱🐱" ANSI_NORMAL "🐱🐱" ANSI_NORMAL, 5, 90);
|
||||
puts(h);
|
||||
assert_se(streq(h, "🐱…" ANSI_NORMAL "🐱" ANSI_NORMAL));
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_INFO);
|
||||
|
||||
Reference in New Issue
Block a user